Skip to content

Keyboard Navigation

import { Aside } from ‘@astrojs/starlight/components’;

notectl provides comprehensive keyboard navigation that mirrors native text editing behavior across platforms. This guide covers all movement, selection, and deletion shortcuts.

notectl uses three selection types to represent the cursor position:

TypeDescriptionWhen it occurs
CollapsedA single cursor position (anchor = head)Normal text editing
RangeA span from anchor to headShift+arrow, click-drag, Select All
NodeSelectionAn entire void block is selectedArrow into an image, horizontal rule, etc.
GapCursorSelectionVirtual cursor at a void-block boundaryArrow past a NodeSelection to a position with no text block
ActionMacWindows / Linux
Move one character rightArrowRightArrowRight
Move one character leftArrowLeftArrowLeft
Extend selection rightShift+ArrowRightShift+ArrowRight
Extend selection leftShift+ArrowLeftShift+ArrowLeft

Character movement counts grapheme clusters (not code points), so multi-byte emoji and combining characters are traversed as single units. Movement crosses block boundaries — pressing ArrowRight at the end of a paragraph moves into the next block.

ActionMacWindows / Linux
Move one word rightAlt+ArrowRightCtrl+ArrowRight
Move one word leftAlt+ArrowLeftCtrl+ArrowLeft
Extend one word rightShift+Alt+ArrowRightCtrl+Shift+ArrowRight
Extend one word leftShift+Alt+ArrowLeftCtrl+Shift+ArrowLeft

Word movement uses the browser’s Selection.modify() API to respect the platform’s word-boundary rules (e.g. punctuation handling differs between macOS and Windows).

ActionMacWindows / Linux
Move to line startCmd+ArrowLeftHome
Move to line endCmd+ArrowRightEnd
Extend to line startCmd+Shift+ArrowLeftShift+Home
Extend to line endCmd+Shift+ArrowRightShift+End
Move one line upArrowUpArrowUp
Move one line downArrowDownArrowDown
Extend one line upShift+ArrowUpShift+ArrowUp
Extend one line downShift+ArrowDownShift+ArrowDown

Line start/end refers to the visual line (soft-wrapped), not the block boundary. In a long paragraph that wraps to three lines, Home moves to the start of the current visual line, not to offset 0 of the block.

ActionMacWindows / Linux
Move to document startCmd+ArrowUpCtrl+Home
Move to document endCmd+ArrowDownCtrl+End
Extend to document startCmd+Shift+ArrowUpCtrl+Shift+Home
Extend to document endCmd+Shift+ArrowDownCtrl+Shift+End

Void blocks (images, horizontal rules, etc.) cannot hold a text cursor. When you arrow into a void block, notectl transitions through selection types:

Text cursor → NodeSelection → GapCursor → Text cursor (next block)
  1. Arrow into a void block — the block becomes a NodeSelection (visually highlighted).
  2. Arrow past the void block — if there is a text block on the other side, the cursor lands there. If not (e.g. two consecutive void blocks), a GapCursor appears at the boundary.
  3. Type at a GapCursor — a new paragraph is inserted with the typed character.
  4. Enter at a GapCursor — an empty paragraph is inserted.

The gap cursor is a virtual cursor at void-block boundaries. It appears as a blinking horizontal line.

KeyAction
ArrowLeft / ArrowUpNavigate away (previous position)
ArrowRight / ArrowDownNavigate away (next position)
EnterInsert new empty paragraph
BackspaceDelete adjacent void block (after side) or navigate
DeleteDelete adjacent void block (before side) or navigate
Any characterInsert paragraph with that character

See the Gap Cursor plugin documentation for details.

Inside tables, navigation is scoped to the current cell with some special shortcuts:

KeyAction
TabMove to next cell (creates a new row at the end of the table)
Shift+TabMove to previous cell
ArrowUp / ArrowDownMove between rows when at cell boundary

Table cells are isolating — word movement and line-boundary movement do not escape the current cell.

ActionMacWindows / Linux
Delete backward (character)BackspaceBackspace
Delete forward (character)DeleteDelete
Delete word backwardAlt+BackspaceCtrl+Backspace
Delete word forwardAlt+DeleteCtrl+Delete
Delete to line startCmd+Backspace
Delete to line endCmd+Delete

At a block boundary, Backspace merges the current block into the previous one; Delete merges the next block into the current one.

All horizontal navigation commands are RTL-aware. In a right-to-left block:

  • ArrowLeft moves forward in offset space (toward the end of text)
  • ArrowRight moves backward in offset space (toward the start of text)

This mapping is automatic and per-block — a document can mix LTR and RTL blocks, and each block gets the correct arrow behavior.

The Caret Navigation plugin announces block-type transitions to screen readers. When the cursor moves into a different block, users hear the block type (e.g. “Heading level 2”, “Bullet list item”, “Code block”). These announcements are:

  • Debounced (150 ms) to avoid noise during rapid arrow-key navigation
  • Suppressed when another plugin has already made an announcement
  • Skipped for the initial focus (no announcement on first render)