v1.3.0
  1. ds
  2. Components
  3. Command palette

Command palette

Ctrl+K search over pages and actions.

This site's own search. Also opens with "/".

fin1te.com, topo and this site each have one. It is a native dialog with a combobox input and a listbox. The script is not on the page until you open it for the first time, so it costs nothing on load.

Structure

<dialog class="palette" aria-label="Command menu">
  <div class="pbox">
    <input type="text" role="combobox" aria-expanded="true" aria-controls="pl" placeholder="Jump to a page, post or action" />
    <ul id="pl" role="listbox">
      <li class="pg" role="presentation">Pages</li>
      <li role="option" id="pi-0" aria-selected="true"><span>Work</span><span class="ph">/work</span></li>
      <li role="option" id="pi-1" aria-selected="false"><span>Writing</span><span class="ph">/writing</span></li>
    </ul>
    <div class="pf"><span><kbd>↑</kbd><kbd>↓</kbd> move</span><span><kbd>↵</kbd> open</span><span><kbd>esc</kbd> close</span></div>
  </div>
</dialog>

Loading it lazily

addEventListener('keydown', (e) => {
  if (e.key === 'k' && (e.metaKey || e.ctrlKey)) {
    e.preventDefault();
    import('./palette.js').then((m) => m.open());
  }
});
ClassOnWhat it does
.palettedialogCentred at 14vh, 35rem wide.
.pboxdivThe surface: input, list, footer.
.pgliGroup heading.
[role=option][aria-selected=true]liActive row, with an accent bar on the left.
.ph / .pe / .pfspan, li, divRow hint, empty message, footer with keys.
.dense.pboxA 40px field and 28px options with an icon, a hint and a kbd shortcut.
[role=option][aria-disabled=true]liA command that cannot run now: dimmed, still listed.

Dense

Light
  • New sessionin ~/work/checkoutAlt N
  • Fork session from the last turn
  • Export session as Markdown
  • Retry queue fixrunning · 4m
  • Rename the billing columns in the warehouse schema and backfill the history2h
  • Approve all pendingnothing pending
↑↓ move↵ runesc close
Dark
  • New sessionin ~/work/checkoutAlt N
  • Fork session from the last turn
  • Export session as Markdown
  • Retry queue fixrunning · 4m
  • Rename the billing columns in the warehouse schema and backfill the history2h
  • Approve all pendingnothing pending
↑↓ move↵ runesc close
390px, dark
  • New sessionin ~/work/checkoutAlt N
  • Fork session from the last turn
  • Export session as Markdown
  • Retry queue fixrunning · 4m
  • Rename the billing columns in the warehouse schema and backfill the history2h
  • Approve all pendingnothing pending
↑↓ move↵ runesc close
Code
<div class="pbox dense" style="box-shadow:none">
  <input type="text" role="combobox" aria-expanded="true" aria-label="Command" placeholder="Run a command, open a session or a file" value="ses" />
  <ul role="listbox" aria-label="Results">
    <li class="pg" role="presentation">Actions</li>
    <li role="option" aria-selected="true"><svg class="i" viewBox="0 0 24 24" aria-hidden="true"><path d="M5 12h14"/><path d="M12 5v14"/></svg><span>New session</span><span class="ph">in ~/work/checkout</span><kbd class="kbd">Alt N</kbd></li>
    <li role="option" aria-selected="false"><svg class="i" viewBox="0 0 24 24" aria-hidden="true"><line x1="6" x2="6" y1="3" y2="15"/><circle cx="18" cy="6" r="3"/><circle cx="6" cy="18" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg><span>Fork session from the last turn</span><span class="ph"></span></li>
    <li role="option" aria-selected="false"><svg class="i" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 3v12"/><path d="m17 8-5-5-5 5"/><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/></svg><span>Export session as Markdown</span><span class="ph"></span></li>
    <li class="pg" role="presentation">Sessions</li>
    <li role="option" aria-selected="false"><svg class="i" viewBox="0 0 24 24" aria-hidden="true"><path d="M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z"/></svg><span>Retry queue fix</span><span class="ph">running · 4m</span></li>
    <li role="option" aria-selected="false"><svg class="i" viewBox="0 0 24 24" aria-hidden="true"><path d="M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z"/></svg><span>Rename the billing columns in the warehouse schema and backfill the history</span><span class="ph">2h</span></li>
    <li role="option" aria-selected="false" aria-disabled="true"><svg class="i" viewBox="0 0 24 24" aria-hidden="true"><path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"/></svg><span>Approve all pending</span><span class="ph">nothing pending</span></li>
  </ul>
  <div class="pf"><span><kbd>↑</kbd><kbd>↓</kbd> move</span><span><kbd>↵</kbd> run</span><span><kbd>esc</kbd> close</span></div>
</div>

.pbox.dense is the palette for a workbench: a 40px field at 13px and 28px options at 12px. An option can carry an icon, the label (it truncates), a hint and a shortcut. A command that cannot run now stays in the list, dimmed, with aria-disabled and a hint that says why.

Accessibility

  • The input keeps focus; aria-activedescendant points at the active option.
  • Match on prefix, then substring, then subsequence, so "ckh" finds ClickHouse.