Writing: blocks, the editor and the keyboard
You write in blocks. A paragraph is a block, and so is a heading, a bullet, an image, a table, a code fence. Every block carries an identity of its own — that is what lets another page point at exactly this line — and every block can be turned into a block of another kind without retyping its text.
There are three ways to make one: type / and pick it from a list, type the
Markdown you already have in your fingers at the start of a line, or turn the
block you are standing in into something else with a chord. All three run the
same conversion, so all three behave the same way on the awkward cases.
The block palette
Type / at the start of a line, or after a space, and the palette opens. Keep
typing to narrow it. Entries match on their name in your language and on
their English name, so /toggle, /code, /image and /quote find their
entries in a German interface too.
↑ and ↓ move, Enter or Tab take the highlighted entry, Esc closes the
palette and leaves the / you typed standing as text. A / inside a code block
opens nothing, and neither does one in the middle of a word — and/or is just a
word.
Nineteen entries, in the order the menu lists them:
| Entry | What it does |
|---|---|
| Text | Turns the line into a plain paragraph. |
| Heading 1 · Heading 2 · Heading 3 | Three levels, and there is no fourth. |
| Bulleted list | An unordered list. |
| Numbered list | An ordered list. |
| To-do list | A checklist with tick boxes. |
| Toggle | A collapsible section. The line’s text becomes its summary. |
| Callout | A highlighted note with an icon slot; you pick the icon in the block. |
| Table | A plain table: a header row, two body rows, three columns. |
| Quote | A block quote. |
| Code | A code block with syntax highlighting. |
| Diagram (Mermaid) | A code block in the mermaid language, drawn as a picture under its source. |
| Divider | A horizontal rule. |
| Image | Asks for an address and inserts the image. |
| File | Opens your device’s file dialog and attaches what you choose. |
| Database | A database with a table view, inside this page. Databases are their own subject and have their own guide. |
| Copy block reference | Copies this block so it can be embedded elsewhere. |
| Paste block reference | Embeds the block you last copied, read-only. |
The last two entries are not blocks. They act on a clipboard of their own: one remembers a block, the other plants a live, read-only view of it somewhere else. References have their own guide; the palette is only the door.
A Table is not a Database. The table is a grid of text that lives in the page and travels with it as Markdown. A database is a set of pages seen as rows, with typed columns and saved views. They look alike for about four seconds.
Typing a block into being
Read this paragraph before the table, because two triggers are not what you
expect: > makes a collapsible section, and the quote is " . Quoting was
moved off > deliberately, to free the character every outline tool uses for
folding.
| You type | You get |
|---|---|
# ## ### |
Heading 1, 2, 3. |
> |
A toggle. The text already on the line becomes its summary; inside a list, the item is split out and takes its children into the toggle’s body. |
" |
A quote. |
1. |
A numbered list. |
- * + |
A bulleted list. |
[] [ ] [x] |
A to-do list. All three spellings start it unticked — [x] is another way to type the trigger, not a way to tick the box. |
``` or ```ts |
A code block, highlighted in that language. |
--- |
A divider. The third hyphen is enough; no space needed. |
=> |
The character ⇒. |
Only 1. starts a numbered list. A line that begins 42. or 2026. is
ordinary text and stays ordinary text — the rule used to accept any number, and
it did not even keep the number: the list restarted at 1 and the digits you had
typed were thrown away.
One undo gives back exactly what you typed, trailing space included. Press
Ctrl/Cmd + Z right after an auto-format and you get # , > , 1. ,
back as characters, with the caret at the end of them — not an empty line. That
was true of four of the six triggers until it was measured on six fresh pages on
16 August 2026 and made true of all six; one gesture behaving two ways depending
on the block type is worse than either behaviour.
The arrow substitution has its own way back: Backspace immediately after it
restores the literal =>. Neither it nor any of the block triggers fires inside
a code block or inside an inline code span, where => is an arrow function and
- is a diff.
Formatting text
Select text and a small toolbar appears over it: bold, italic, strikethrough, inline code, highlight, text colour, link. Every button says its chord in its tooltip.
Text colour is a row of ten swatches and has no chord, and that is a decision rather than an omission: a colour is a choice out of a closed palette — grey, brown, orange, yellow, green, blue, purple, pink, red, plus Default colour to take one off — so a single key could only ever mean “the last one”, which is a shortcut for something you did not ask to repeat. The swatches open as a second row inside the same toolbar; choosing one closes it again.
Ctrl/Cmd + K is the link picker — over a selection. With nothing
selected the same chord opens search, which is deliberate: a link needs text to
attach to. The picker searches pages and also takes a pasted address.
A typed URL does not become a link on its own, and neither does a pasted one
turn itself into a card behind your back. Pasting a URL over a selection makes
the selected text a link; pasting one on an empty spot inserts the plain link
straight away and offers three other shapes beside it (a title, a bookmark card,
an embed). Ignore the offer, type on, or press Esc, and you keep the plain
link. Only the three other shapes make this instance fetch anything from the
other end.
The formatting toolbar stays out of code blocks, where there are no marks to set.
The block menu
The ⋯ in the left margin is where the verbs that act on a whole block live.
Three ways to open it, and the first is why it exists at all:
- The caret. Whichever block holds the caret shows its
⋯and keeps showing it. Tap the block, then tap the⋯. - Hover, on a device that has a pointer: the same
⋯follows the block under it. Ctrl/Cmd+/, which opens it on the block the caret is in.
It is deliberately not a long press: inside text, long press is the platform’s own select-a-word gesture, and taking it over would trade one missing affordance for a broken one people use far more often.
| Entry | When it appears |
|---|---|
| Copy reference | Always, including on a page you can only read — capturing a block’s identity changes nothing. |
| Copy link to heading | On a heading. |
| Collapse section / Expand section | On a heading that has something under it. |
| Collapse sub-items / Expand sub-items | On a list item that has children. |
| Wrap long lines / Don’t wrap long lines | On a code block. |
| Duplicate | Where a second copy may legally sit beside the first. |
| Move up / Move down | Where there is somewhere to move to. |
| Indent / Outdent | On a list item, where the move is possible. |
| Insert row above / below · Delete row · Insert column left / right · Delete column | With the caret in a table. |
| Turn into → … | See below. |
| Delete | Always, on a page you can edit. |
A row that is missing is a move that would do nothing. Every entry that moves or re-types a block is asked first, without being run, and only offered if it answers yes — so the absence of Outdent on a top-level bullet means the key would have declined too. The buttons do exactly what the keyboard does, no more.
The two view entries are offered to readers as well. Folding a long section and unwrapping a wide code block describe your screen, not the document: they never reach the page, the Markdown or anybody else, so someone who can only read the page can still do both.
It is not where a block is configured. Per-type settings — an image’s width and alignment, for instance — sit on the block’s own toolbar when the block is selected, next to the thing they change. That line is not stylistic: a setting travels with the document, every reader sees it and changing it is an edit, while a view state describes one screen and reaches nothing.
Turn into
The conversions on offer depend on what you are standing in. A plain paragraph or heading offers eleven — text, the three heading levels, the three lists, quote, callout, code, toggle — minus the one it already is, which is never offered back to you. A code block offers only text and the headings — a code block inside a bullet is a shape the document model refuses, so offering it would be a menu entry that silently does nothing. A list item offers the three list kinds and Toggle; a quote, a toggle, an image and a divider offer nothing at all.
Select several blocks and the list gets shorter, on purpose. A run offers text, the three heading levels and the three list kinds — and not quote, callout, toggle or code, because each of those has two defensible readings (one container holding all three blocks, or three containers?) and an entry that guesses is worse than an entry that is absent. You find out which reading it took only after it has rewritten your document.
A run must also be of one kind: all plain textblocks, or all items of the same list. A mixed selection offers nothing, and the block-by-block route still works.
Moving a block
Alt + ↑ / Alt + ↓ moves the block the caret is in. The unit is the
list item when you are in a list, and the top-level block otherwise, which makes
it the universal “move this”. Move up and Move down in the ⋯ are the same
command with a second trigger, for a keyboard without Alt and for a finger.
At the edge of a list, the move re-types the row instead. Standing on the last bullet with a numbered list right below it, the first press makes the row a numbered one and carries it into that list — it was already adjacent, so there was nowhere to swap it to; a second press then moves it inside its new list.
A move never parks a block where you cannot see it. If the destination is inside a folded section, the fold opens in the same step. Without that, one press appeared to swallow the block and the shortcut then looked dead, because the caret had been pushed out of the hidden text along with it.
Ctrl/Cmd + Shift + ↑ / ↓ used to be bound to the same command and was
withdrawn: the operating system already owns it for extending the selection to
the start or end of the document, and an editor is the one place that has to
keep working.
Dragging works from the grip in the left margin. The whole block comes with it, the line shows where it will land, and a row dropped into a list of another kind adopts that kind. Pressing the grip without dragging selects the block, which is the pointer’s way to “act on this whole block”.
The grip is the first thing to go when the window is narrow: the margin is
drawn outside the text column, and when there is only room for two lanes the
grip is dropped and the ⋯ moves inward, into the lane the grip leaves free —
so the margin stays two lanes wide instead of reaching past the edge of the
screen. It is the right one to lose — it is the only affordance in that margin
with a full keyboard equivalent, and the drag it is built on does not fire from
a finger at all.
Folding
A fold caret appears in the margin of every heading that has something under it and every list item that has children. Clicking it folds; the blocks do not move, they are simply not drawn.
- A heading folds down to the next heading of the same level or higher, within the same container.
- A list item folds its own children.
- A paragraph has nothing to fold and gets no fold caret. The block that means “I want this text to be foldable” already exists and is called a toggle; Turn into → Toggle is in the block menu of any paragraph.
- A toggle folds at its own fold caret, or with
Ctrl/Cmd+Enterwhile the text caret is on its summary line.
Ctrl/Cmd + Alt + T is not quite symmetrical, and it is worth knowing
which half you are getting. With nothing folded it folds every heading and
every list item — and not the toggles, which are a different mechanism. With
anything folded at all it unfolds everything, toggles included.
Folding is per device and it is remembered. It reaches neither the document,
the Markdown nor anybody else’s screen — a colleague opening the same page sees
their own folds — but it survives a reload on the machine you folded on, for the
fifty pages you most recently folded something on. Nothing you cannot see can be
edited into: the caret is pushed out of hidden text, a selection that reaches
into it opens it first, and Backspace at the seam expands rather than merging
invisible text into visible text.
Images and files
Three ways in, because two of them are not available to everyone:
- Drop a file on the page, or paste one. Images land as images; everything else lands as a link to the stored file, named after it.
/imageasks for an address. Cancelling —Esc, the button, a click outside, an empty field — inserts nothing, which is what cancelling means./fileopens your device’s file dialog. It exists because dragging is not a gesture on a phone and not a gesture from a keyboard.
A dropped file lands where the line was drawn, including inside the bullet you dropped it on. If the upload fails, the editor says so and inserts nothing.
A selected image has its own toolbar: three alignments, four widths (25, 50, 75, 100 % of the column), Original size, and a grip on its right edge that you can also drive with the arrow keys. Width and alignment are document content — they travel in the page’s Markdown, every reader sees them, and changing one is an edit.
An image whose bytes live elsewhere carries an External image · host
badge, always visible and low-contrast, because the person who needs to know
is the one who did not insert it. Four things follow from that badge, and they
are the reason it is there: the other end learns who read the page and when,
every time the page is drawn; the bytes can change or vanish under the page
without anyone editing it; the image is not in a workspace export or backup;
and a plain http:// address will not load at all.
A file is a link, not a block. Attaching one writes a link whose target is the stored file, so it can sit in a sentence, in a bullet or in a table cell, and it travels with the text it is written in. The document records the file’s identity and not the address it is served from, which is why the same page works whoever opens it.
Tables, code and diagrams
A table starts as a header row and two body rows, three columns wide. Tab
walks the cells, and Tab in the last cell appends a row. Adding and removing
rows and columns is in the block menu rather than on six chords of its own — a
grid whose structure can only be changed with a mouse, aiming at cells that may
be a pixel high, is not a grid you can use. Cells hold one paragraph each and
cannot be merged.
A code block takes its language from the fence you type: ```ts and a
space gives you a highlighted TypeScript block. Long lines wrap by default. You
can flip one block from its ⋯ — Don’t wrap long lines — which lasts until you
reload, and set the lasting preference for your device under Settings →
Preferences → Long code lines. Both are about your screen and change nothing
in the page.
A diagram is a code block in the mermaid language, drawn as a picture
underneath its still-editable source. /mermaid starts you off with a working
three-node flowchart rather than an empty fence, because the point of the entry
is to show you what the syntax does. A diagram that cannot be parsed says so
under its source — Diagram cannot be drawn: … — instead of vanishing, and the
same fence renders as a diagram in any other Markdown tool that draws them.
Markdown in and out
Copying blocks puts canonical Markdown on the clipboard, so a paste into a terminal, an editor or a chat window is text a human wrote rather than a flattening of the screen. Pasting inside Basalt keeps the richer form and the blocks’ identities.
Pasting text that looks like Markdown — a heading, a list, a fence, a table —
turns it into real blocks. Two escape hatches: Ctrl/Cmd + Shift + V
pastes as literal text, which is also the way to get a # or a - into a
document as characters, and a paste into a code block is always verbatim.
The keyboard
Everything below is bound. Where a chord is a second spelling of another, it is named in the footnotes rather than given a row of its own.
| Keys | What they do |
|---|---|
Ctrl/Cmd + B / I / E |
Bold / italic / inline code. |
Ctrl/Cmd + Shift + S / H |
Strikethrough / highlight. |
Ctrl/Cmd + K with text selected |
The link picker. With nothing selected the same chord opens search. |
/ |
Insert a block. |
@ |
Link a page or mention a person. |
[[ / ![[ |
Link a page / embed a page. |
Ctrl/Cmd + / |
This block’s menu. |
Ctrl/Cmd + Alt + 0 … 8 |
Turn the block into text, heading 1, 2, 3, a to-do list, a bulleted list, a numbered list, a toggle, a code block. One uninterrupted run. |
Ctrl/Cmd + Enter |
Modify this block: tick a to-do, fold a toggle, open a page link. Elsewhere it stays a line break, and in a code block it still steps out. |
Esc |
Select the whole block. |
Alt + ↑ / ↓ |
Move the block up or down. |
Tab / Shift + Tab |
Indent / outdent a list item. In a table, walk to the next cell. |
Ctrl/Cmd + Alt + T |
Fold or unfold — see Folding. |
Ctrl/Cmd + Z / Ctrl/Cmd + Shift + Z |
Undo / redo. |
Ctrl/Cmd + Shift + V |
Paste as plain text. |
Ctrl/Cmd + K |
Search the workspace. |
Ctrl/Cmd + F |
Search the document in front of you — where there is one. On a screen with nothing to narrow to it stays the browser’s find bar, which is why the help sheet draws that row only where it is true. |
Ctrl/Cmd + Alt + 9 |
A new page. |
Alt + click |
Peek at a page from the sidebar, without going there. |
? |
The keyboard help sheet. Not while you are typing — ? is a character. |
Five things the table cannot say in a cell:
- Each block chord also reverts. Pressing
Ctrl/Cmd+Alt+5on a bullet turns it back into a paragraph; on an indented item it outdents one level, which is the answerShift+Tabalready gives. - Older spellings still work.
Ctrl/Cmd+Shift+7/8/9for the numbered, bulleted and to-do lists,Ctrl/Cmd+Alt+Cfor a code block,Ctrl/Cmd+Shift+Bfor a quote, andCtrl/Cmd+Yfor redo. Nothing was taken away when the taught chords changed. - The digits are
Ctrl/Cmd+Altand notCtrl/Cmdalone because on macOS⌘1…⌘9switches browser tabs and never reaches the page — a chord that works on one platform and is invisible on the other is not a chord. - On a German keyboard, three of them do not arrive. Windows and Linux
report
AltGrasCtrl+Alt, and on a German layoutAltGr+7/8/9is how you type{,[and]— soCtrl+Alt+7,8and9write those characters instead of making a toggle, a code block or a page.Ctrl+Alt+Thas the same shape of problem on GNOME, where the window manager takes it for a terminal before the browser sees it. Nothing is broken, only unreachable: the block menu turns a block into a toggle or a code block, folding is at the fold carets and in the block menu, and the+on a collection row in the sidebar makes a page. On macOS⌘+⌥is notAltGrand all of them work. Ctrl/Cmd+/opens the help sheet everywhere else in the app. Inside a document it is the block’s own menu, and the sheet is on?.
On a phone
The layout is the desktop one, one surface at a time, and the editor keeps every verb it has:
- The block menu is the whole story. Tap a block and its
⋯appears in the margin and stays; tap it and the menu opens as a sheet from the bottom edge, so the block it acts on is still visible above it. Anchoring it to the block was tried and does not work: measured on a phone-sized screen the menu is two thirds of the screen tall, fits neither above nor below, and ended up in the top corner, up to 357 px away from the block it belonged to. - Indent, outdent and the moves are rows in that menu, and they are there
because a software keyboard has no
Tab. Until those rows existed a nested list could not be made on a phone at all. - There is no drag grip, because there is no room for a third lane and
because the drag it is built on does not fire from a finger. The
⋯and the fold caret are what the margin holds. - Nothing of ours floats over the keyboard. The controls sit in the document, where nothing has to guess where the keyboard ends.
What the editor cannot do yet
- No columns and no side-by-side layout. A page is one column of blocks.
- No way to change a code block’s language after the fact. The language comes from the fence you typed, so retype the fence — or paste the block back in as Markdown with the language you want.
- No control for a table’s column alignment. Alignment survives the round trip through Markdown and a new row inherits its column’s, but nothing in the editor sets it. Cells cannot be merged either, and that one is a decision: the Markdown a page must round-trip through has no way to write a merged cell down.
- No colour on a block. Text colour and highlight apply to text inside a block; a block itself has no background of its own. A callout is the block for “this paragraph is different”.
- No synced blocks beyond references. A pasted block reference is read-only where it sits and is edited at its home. That is the design, not a gap.
- A comment must sit inside a single block of text. A selection that spans two blocks, or an image, cannot be anchored, and the app says so rather than attaching the thread somewhere approximate.