Skip to content

feat: table block type #184

Description

@oobagi

Context

The block editor currently supports 10 block types: Paragraph, Heading1-3, BulletList, NumberedList, Checklist, CodeBlock, Quote, and Divider. Tables are a common markdown element with no support today — they can't be created, parsed, rendered, or edited.

Goal

Add a Table block type that supports creating, editing, rendering, and round-tripping markdown tables through the existing block pipeline.

Markdown format

Standard GFM pipe tables:

| Name  | Role    |
| ----- | ------- |
| Alice | Engineer|

Architecture fit

Each block type touches these layers — table would follow the same pattern:

  1. internal/block/block.go — Add Table constant to BlockType enum, String(), Short() (e.g. tb)
  2. internal/block/parse.go — Detect |-prefixed lines, group consecutive table rows into one Table block. Store raw pipe-delimited content in Block.Content
  3. internal/block/serialize.go — Emit pipe table markdown from Block.Content, auto-pad column widths
  4. internal/editor/palette.go — Add Table entry to the / command palette
  5. internal/editor/render.go — Render table with box-drawing borders (inactive + active + view mode). Active mode needs per-cell cursor navigation
  6. internal/theme/theme.go — Add TableStyle struct (border color, header style, alignment)

Design considerations

  • Data model: Store table as a flat string in Block.Content using pipe syntax (| col1 | col2 |\n| --- | --- |\n| val1 | val2 |). The parser and renderer interpret it; no new struct fields needed beyond Content
  • Editing: The hardest part. Options in order of complexity:
    1. Phase 1 — raw text editing: Edit the pipe-delimited text as-is in a single textarea (like CodeBlock). Simple, ships fast, already works for power users
    2. Phase 2 — grid navigation: Tab/Shift+Tab to move between cells, auto-pad columns on blur. Requires custom cursor logic within the textarea
    3. Phase 3 — structural ops: Add/remove rows/columns via keyboard shortcuts (e.g. Ctrl+Shift+R for row, Ctrl+Shift+C for column)
  • Rendering: Use box-drawing characters (similar to CodeBlock's bordered box) for inactive/view mode. Header row rendered bold
  • Column alignment: Parse the ---/:---/:---:/---: separator to determine left/center/right alignment
  • Word wrap: Tables should not wrap — horizontal scroll (like CodeBlock in no-wrap mode) is more appropriate

Tasks

  • Add Table to BlockType enum with String() and Short() methods
  • Parse pipe tables in parse.go — detect |-prefixed lines, group into single block
  • Serialize tables in serialize.go with auto-padded columns
  • Round-trip tests: Parse(Serialize(Parse(table_md))) == Parse(table_md)
  • Add Table entry to / command palette with default 2x2 template
  • Render inactive table with box-drawing grid and bold header
  • Render active table (Phase 1: raw textarea editing)
  • Render view mode table
  • Add TableStyle to theme system
  • Update blockPrefixWidth() and isMultiLine() for Table type
  • Handle isBlockStart() detection for table lines
  • Integration test: create table via palette, edit, save, reload

Out of scope (future)

  • Cell-level cursor navigation (Phase 2)
  • Structural add/remove row/column shortcuts (Phase 3)
  • Column resizing
  • Merged cells

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions