genesis-editor

Columns

Google Docs–style two- and three-column layouts: an image beside a heading and body, not a table of images. MIT, not BlockNote XL.

Inserting#

Type /Columns for two columns, or /3 columns for three. The formatting toolbar's Columns button inserts two. Each column is a normal nest of blocks — paragraph beside paragraph, code beside text, image beside a heading, list beside a quote. Drag the handle between columns to change their widths. On viewports under 640px the columns stack.

A columnList is a finite section. Enter at the end of a column (empty last block) or click below the layout continues as a full-width sibling after it, not more nested blocks in the last column. Columns are not CSS float on a single image, and not a BlockNote table (those cells are inline-only). They are not @blocknote/xl-multi-column (GPL-3.0 / commercial).

// Slash: /Columns (two) or /3 columns
// Toolbar: Columns inserts two
<BlockEditor tools={["heading", "image", "columns", "bold"]} />
// Omit "columns" (or set columns: false) to turn the block off.
Inserting columns while the caret is already inside a column places the new layout after the current one, so columns do not nest. Turn the tool off with tools that omit "columns"; existing layouts flatten to their inner blocks when they load.

Paste and import#

HTML from Google Docs or Word becomes columns when it is clearly a layout, not a data table:

  • A one-row table of two or three cells with an image on one side and a heading or several paragraphs on the other (the screenshot case: product image left, heading and body right).
  • A floated <img> or <figure> (float:left / right, or align="left" / right) with wrapping text beside it.

Image grids, multi-row tables, and a cell that is only a short caption stay tables, including inline images in table cells. Two text-only columns without data-genesis-columns are not converted.

HTML export#

Export is an email-safe <table role="presentation"> marked data-genesis-columns and data-genesis-column-widths, so Gmail and Word keep the row and parseHTML reads it back as columns. Column bodies are ordinary semantic HTML inside each <td>.

<table data-genesis-columns="2" data-genesis-column-widths="40,60" role="presentation"
       style="width:100%;border-collapse:collapse;table-layout:fixed">
  <colgroup><col style="width:40%"><col style="width:60%"></colgroup>
  <tbody><tr>
    <td style="width:40%;vertical-align:top">…</td>
    <td style="width:60%;vertical-align:top">…</td>
  </tr></tbody>
</table>

Block JSON

{
  "type": "columnList",
  "children": [
    { "type": "column", "props": { "width": 40 }, "children": [{ "type": "image", "props": { "url": "/examples/lake.png" } }] },
    { "type": "column", "props": { "width": 60 }, "children": [
      { "type": "heading", "props": { "level": 3 }, "content": "Mountain lake" },
      { "type": "paragraph", "content": "The same blocks as the rest of the document." }
    ]}
  ]
}