Files

13 KiB
Raw Permalink Blame History

Create Tables

Part of the figma-use-figjam skill. Creating and styling tables with rows, columns, and cell content.

Scope: Tables are FigJam-specific nodes created with figma.createTable(). They structure content in rows and columns. For stickies and sections, see create-sticky and create-section. For shapes with text in them, see create-shape-with-text.

When to use this skill: Prefer FigJam tables whenever the user asks for a table, spreadsheet, comparison grid, roster, or any row/column layout of text data. Examples: "create a table", "add a spreadsheet", "make a grid with names and roles", "comparison table", "team roster", "data table". Do not build a table-like layout out of shapes with text or other node types.

When NOT to use this skill: Prefer creating other node types or relying on node positioning on the canvas in order to organize non-text content.

Note: The Table API is only available in FigJam.

Creating a Table

Default to applying a dark color to the header row(s) but leave the other cells to have the default fill (without making any edits), unless the user provides guiddance on styling.

CRITICAL: If the user provides real data to include (e.g. in the form of CSV, image, etc.), include all of it in the resulting table. Never intermix real data with placeholder data. Otherwise if no data is provied, create tables without any placeholder content in headers, rows, columns, or cells.

CRITICAL: Never delete any source data from the canvas when asked to convert to a table.

// Default: 2 rows, 2 columns, parented under figma.currentPage
const table = figma.createTable()

// Or specify dimensions: createTable(numRows?, numColumns?)
const table3x4 = figma.createTable(3, 4)

console.log('Created table:', table.id, table.numRows, 'x', table.numColumns)
figma.closePlugin()

Setting Cell Text

Each cell is a TableCellNode with a text sublayer (TextSublayerNode). You must load the font before setting characters. Use table.cellAt(rowIndex, columnIndex) to get a cell (indices are zero-based).

const table = figma.createTable(2, 3)

// Load the font before setting characters
await figma.loadFontAsync(table.cellAt(0, 0).text.fontName)

// Set characters for each cell (example: header row A B C, data row 1 2 3)
table.cellAt(0, 0).text.characters = 'A'
table.cellAt(0, 1).text.characters = 'B'
table.cellAt(0, 2).text.characters = 'C'
table.cellAt(1, 0).text.characters = '1'
table.cellAt(1, 1).text.characters = '2'
table.cellAt(1, 2).text.characters = '3'

table.x = 0
table.y = 0

figma.closePlugin()

Modifying Text in an Existing Table

const table = await figma.getNodeByIdAsync('123:456')
if (table && table.type === 'TABLE') {
  const cell = table.cellAt(0, 0)
  await figma.loadFontAsync(cell.text.fontName)
  cell.text.characters = 'Updated'
}
figma.closePlugin()

TableNode Properties

  • type: 'TABLE' (readonly)
  • numRows, numColumns: number (readonly) — number of rows and columns
  • cellAt(rowIndex, columnIndex): returns the TableCellNode at that position
  • width, height: number (readonly) — use resizeRow / resizeColumn to change size

Adding and Removing Rows/Columns

const table = figma.createTable(2, 2)

// Insert a row before index 1 (so new row is at index 1)
table.insertRow(1)

// Insert a column before index 0
table.insertColumn(0)

// Remove row at index 2, column at index 0
table.removeRow(2)
table.removeColumn(0)

figma.closePlugin()

Moving Rows and Columns

const table = await figma.getNodeByIdAsync('123:456')
if (table && table.type === 'TABLE') {
  // moveRow(fromIndex, toIndex) — move row from fromIndex to toIndex
  table.moveRow(2, 0)

  // moveColumn(fromIndex, toIndex)
  table.moveColumn(1, 0)
}
figma.closePlugin()

Resizing Rows and Columns

Rows and columns cannot be resized smaller than their minimum size. Use resizeRow(rowIndex, height) and resizeColumn(columnIndex, width).

const table = figma.createTable(3, 3)

// Resize first row to 60px height, first column to 120px width
table.resizeRow(0, 60)
table.resizeColumn(0, 120)

console.log('Table size:', table.width, 'x', table.height)
figma.closePlugin()

TableCellNode Properties

  • type: 'TABLE_CELL' (readonly)
  • text: TextSublayerNode (readonly) — the cell’s text; load font then set text.characters
  • rowIndex, columnIndex: number (readonly) — cell position in the table
  • width, height: number (readonly) — determined by table layout
  • fills: set cell background (e.g. header row styling)

Setting Cell Fills

const h = (r, g, b) => ({ r: r / 255, g: g / 255, b: b / 255 })

const table = figma.createTable(2, 3)
await figma.loadFontAsync(table.cellAt(0, 0).text.fontName)

// Header row: light blue background
for (let c = 0; c < 3; c++) {
  const cell = table.cellAt(0, c)
  cell.fills = [{ type: 'SOLID', color: h(0xc2, 0xe5, 0xff) }] // Light blue #C2E5FF
  cell.text.characters = ['A', 'B', 'C'][c]
}
// Data row
table.cellAt(1, 0).text.characters = '1'
table.cellAt(1, 1).text.characters = '2'
table.cellAt(1, 2).text.characters = '3'

figma.closePlugin()

Table-Level Fills

The table itself has a fills property for the overall table background. Use setFillsAsync for pattern fills; for solid fills you can set table.fills directly.

const h = (r, g, b) => ({ r: r / 255, g: g / 255, b: b / 255 })

const table = figma.createTable(2, 2)
table.fills = [{ type: 'SOLID', color: h(0xff, 0xec, 0xbd) }] // Light yellow #FFECBD

figma.closePlugin()

Color Options

FigJam tables use the same color palette as sections and shapes. You can style:

  • Table fill — table.fills (overall table background)
  • Cell fill — table.cellAt(row, col).fills (per-cell background, e.g. header row)
  • Cell text color — cell.text.fills (set after loading fonts)

Tables do not have strokes. When applying colors, set fill and text together so contrast is correct: dark fills use white text; light fills use dark text. Strongly prefer colors from this list so the table matches the FigJam editor palette.

Color Preset Map

Use this map for table fills and cell fills. For cell text, use the text value (white on dark fills, dark on light fills). CRITICAL: Use hex/255 notation (e.g. 0x66/255) for exact palette matching — rounded decimals cause FigJam to treat the color as "custom" instead of a palette color.

If the user asks for a color by a similar but different name, identify the closest option available from this map, keeping in mind the cell context (e.g. header row, body cell, etc). For example, choose violet if asked for a purple header or lightGreen if asked for green rows.

const h = (r, g, b) => ({ r: r / 255, g: g / 255, b: b / 255 })
const WHITE = h(0xff, 0xff, 0xff)
const DARK = h(0x1e, 0x1e, 0x1e)

const TABLE_COLOR_PRESETS = {
  // Dark fills (e.g. header row) — use white text
  black: { fill: h(0x1e, 0x1e, 0x1e), text: WHITE },
  darkGray: { fill: h(0x75, 0x75, 0x75), text: WHITE },
  green: { fill: h(0x66, 0xd5, 0x75), text: WHITE },
  teal: { fill: h(0x5a, 0xd8, 0xcc), text: WHITE },
  blue: { fill: h(0x3d, 0xad, 0xff), text: WHITE },
  violet: { fill: h(0x87, 0x4f, 0xff), text: WHITE },
  pink: { fill: h(0xf8, 0x49, 0xc1), text: WHITE },
  red: { fill: h(0xf2, 0x48, 0x22), text: WHITE },
  orange: { fill: h(0xff, 0x9e, 0x42), text: WHITE },

  // Light fills (e.g. table background, body cells) — use dark text
  gray: { fill: h(0xb3, 0xb3, 0xb3), text: DARK },
  lightGray: { fill: h(0xd9, 0xd9, 0xd9), text: DARK },
  lightGreen: { fill: h(0xcd, 0xf4, 0xd3), text: DARK },
  lightTeal: { fill: h(0xc6, 0xfa, 0xf6), text: DARK },
  lightBlue: { fill: h(0xc2, 0xe5, 0xff), text: DARK },
  lightViolet: { fill: h(0xdc, 0xcc, 0xff), text: DARK },
  lightPink: { fill: h(0xff, 0xc2, 0xec), text: DARK },
  lightRed: { fill: h(0xff, 0xc7, 0xc2), text: DARK },
  lightOrange: { fill: h(0xff, 0xe0, 0xc2), text: DARK },
  yellow: { fill: h(0xff, 0xc9, 0x43), text: DARK },
  lightYellow: { fill: h(0xff, 0xec, 0xbd), text: DARK },
  white: { fill: h(0xff, 0xff, 0xff), text: DARK },
}

Hex Reference

Color Fill Hex Text
Black #1E1E1E white
Dark gray #757575 white
Gray #B3B3B3 dark
Light gray #D9D9D9 dark
Green #66D575 white
Light green #CDF4D3 dark
Teal #5AD8CC white
Light teal #C6FAF6 dark
Blue #3DADFF white
Light blue #C2E5FF dark
Violet #874FFF white
Light violet #DCCCFF dark
Pink #F849C1 white
Light pink #FFC2EC dark
Red #F24822 white
Light red #FFC7C2 dark
Orange #FF9E42 white
Light orange #FFE0C2 dark
Yellow #FFC943 dark
Light yellow #FFECBD dark
White #FFFFFF dark

white = #FFFFFF, dark = #1E1E1E

Applying Table and Cell Colors

Set table background, then cell fills and text colors. Load the cell font before setting text.fills or text.characters:

CRITICAL: Never clear or remove the fill from a table or cell node. Instead, interpret this as an ask to reset to the default fill color (i.e. white).

const h = (r, g, b) => ({ r: r / 255, g: g / 255, b: b / 255 })
const DARK = h(0x1e, 0x1e, 0x1e)
const preset = {
  fill: h(0xc2, 0xe5, 0xff), // Light blue
  text: DARK,
}

const table = figma.createTable(2, 3)
await figma.loadFontAsync(table.cellAt(0, 0).text.fontName)

// Table-level background
table.fills = [{ type: 'SOLID', color: preset.fill }]

// Header row: dark fill, white text
const headerPreset = { fill: h(0x3d, 0xad, 0xff), text: h(0xff, 0xff, 0xff) }
for (let c = 0; c < 3; c++) {
  const cell = table.cellAt(0, c)
  cell.fills = [{ type: 'SOLID', color: headerPreset.fill }]
  cell.text.fills = [{ type: 'SOLID', color: headerPreset.text }]
  cell.text.characters = ['Name', 'Role', 'Team'][c]
}

// Body row: light fill (or inherit table fill), dark text
for (let c = 0; c < 3; c++) {
  const cell = table.cellAt(1, c)
  cell.text.fills = [{ type: 'SOLID', color: preset.text }]
  cell.text.characters = ['Alice', 'Designer', 'Product'][c]
}

figma.closePlugin()

Changing Color on an Existing Table

const table = await figma.getNodeByIdAsync('123:456')
if (table && table.type === 'TABLE') {
  await figma.loadFontAsync(table.cellAt(0, 0).text.fontName)
  const preset = TABLE_COLOR_PRESETS.lightGreen
  table.fills = [{ type: 'SOLID', color: preset.fill }]
  // Optionally update header or specific cells
  table.cellAt(0, 0).fills = [{ type: 'SOLID', color: preset.fill }]
  table.cellAt(0, 0).text.fills = [{ type: 'SOLID', color: preset.text }]
}
figma.closePlugin()

Building a Table from Data

const rows = [
  ['Name', 'Role', 'Team'],
  ['Alice', 'Designer', 'Product'],
  ['Bob', 'Engineer', 'Platform'],
]
const numRows = rows.length
const numCols = rows[0].length

const table = figma.createTable(numRows, numCols)
await figma.loadFontAsync(table.cellAt(0, 0).text.fontName)

for (let r = 0; r < numRows; r++) {
  for (let c = 0; c < numCols; c++) {
    table.cellAt(r, c).text.characters = rows[r][c]
  }
}

table.name = 'Team roster'

figma.closePlugin()

Cloning Tables

const original = await figma.getNodeByIdAsync('123:456')
if (original && original.type === 'TABLE') {
  const clone = original.clone()
  clone.x = original.x + original.width + 20
  console.log('Cloned table:', clone.id, clone.numRows, 'x', clone.numColumns)
}
figma.closePlugin()

Key Points

  • Always wrap code in an async IIFE: (async () => { ... })();
  • Always call figma.closePlugin() at the end of every code path.
  • Initial table content: Prefer empty tables unless the user provides data; then include all of it (no placeholders) and do not delete source data when converting. Use a dark header row and default fill elsewhere.
  • Follow the canonical text-edit recipe for cell.text.characters and cell.text.fills — load cell.text.fontName (use the first cell’s, or each cell’s if they differ).
  • Set fill and text color together when styling cells — use the color presets so light fills get dark text and dark fills get white text.
  • Use hex/255 notation for palette colors (e.g. h(0xC2, 0xE5, 0xFF)) so FigJam treats them as palette colors, not custom.
  • Table API is FigJam-only — figma.createTable() is not available in Figma Design or other editor types.
  • Indices are zero-based: cellAt(0, 0) is the top-left cell.
  • Table dimensions: width and height are readonly; use resizeRow and resizeColumn to change size. Rows/columns cannot be resized below their minimum.
  • Use node IDs from the user message, not figma.currentPage.selection.
  • Verify changes by logging before/after values when helpful.