Table

Tables sit in a rounded, bordered wrapper that scrolls horizontally when it is wider than the content. Cells are editable, and the buttons that add and remove rows and columns appear on hover.

Installation

This pattern is built from files in @intentui/editor. Install the editor, then copy the code above into a component of your own.

npx shadcn@latest add @intentui/editor

What's included

PieceWhy it is here
RichTextExtensionLexical's rich text behavior. Every pattern needs it.
InitialStateExtensionApplies the seeded content immediately, so the server and the client render the same. Leave it out if your editor starts empty. See Seeding initial content.
TableExtensionRegisters the table nodes, cell selection and keyboard navigation. Remove it and INSERT_TABLE_COMMAND does nothing.
registerMarkdownShortcuts(editor, [TABLE])Converts a typed Markdown row into a table, and converts the seed content in this demo.
InsertTablePluginThe toolbar button with the size grid.
TablePickerPluginThe slash menu items, including sizes.
TableHoverActionsPluginThe add and delete buttons shown when you hover a table.
ComponentPicker, BlockInsert, ToolbarContainers for the slash menu and the button.

Inserting a table

MethodHow
ToolbarThe "Insert table" button opens a grid of up to 10 columns by 8 rows. Hover to choose a size, click to insert.
Slash menuType /, then choose "Insert table" for a 3x3 table.
Slash menu with sizeType / then a size such as /4x5. Sizes are rows by columns, from 1 to 10. A partial number like /4 suggests five sizes.
MarkdownType a row such as | a | b | and press Enter. A following | --- | --- | row marks the previous row as the header.

Inserted tables have a header row and a header column. Empty paragraphs directly before and after a new table are removed.

Editing a table

Hover a table to get buttons from TableHoverActionsPlugin:

  • Over the top row, "Add column" and "Delete column" appear on the top edge, above the closest column.
  • Over the first column, "Add row" and "Delete row" appear on the left edge.
  • Delete buttons are hidden when only one row or column is left.

The buttons are not rendered in read-only mode.

Styling

theme.ts keys:

KeyDefault
tableScrollableWrappereditor-table-scrollable-wrapper relative my-3 w-full overflow-x-auto rounded-lg border border-border ...
tablew-full min-w-full table-fixed caption-bottom text-sm/6
tableRow[&:last-child>*]:border-b-0
tableCelleditor-table-cell relative border-b border-s border-border px-4 py-2 ...
tableCellHeadertext-start font-medium text-muted-foreground

theme.css handles selection: .editor-table-selected gets a 2px var(--primary) outline, and .editor-table-cell-selected::after overlays a var(--primary) tint.