CommandMenu
CommandMenu renders a searchable option list with keyboard navigation, grouping, and async loading.
It executes one command at a time and closes, without retaining a selection. Selection bindings (value), selection limits, chip controls, user-created options, bulk selection, and pasted option lists belong to MultiSelect. Use on_execute={({ action }) => …} to observe commands invoked by menu selection or global shortcut, and on_activate to track keyboard navigation. Replace the former on_add callback with on_execute; it reports invocation, without waiting for asynchronous actions to finish.
Search, grouping, loading, and styling props share OptionListProps with MultiSelect. The labels prop accepts loading_more, loading_failed, retry, and group overrides to localize status messages and group buttons. placeholder, no_matching_options_msg, and default_disabled_title control their respective text separately.
svelte<script lang="ts">
import { goto } from '$app/navigation'
import { resolve } from '$app/paths'
import type { Pathname } from '$app/types'
import { CommandMenu } from 'svelte-widgets'
import { demo_pages } from '../../index'
const resolve_path = resolve as (path: Pathname) => string
const actions = demo_pages.map((route) => ({
id: route,
label: route,
action: () => goto(resolve_path(route)),
}))
</script>
<CommandMenu {actions} triggers={[`n`]} />PageSearch
PageSearch wraps CommandMenu with full-text search over statically generated pages. fallback_actions are matched locally on every keystroke, so known routes show up without waiting on the index. Failed index, search, or result downloads show a Retry button. Successful results remain visible, including those from a partially failed batch; Retry downloads only failed results and restores their search order. Install pagefind as a development dependency, then index the rendered site after the application build. Run this script before previewing or deploying:
{
"scripts": {
"build:site": "vite build && pagefind --site build"
}
}
Open the documentation search with cmd/ctrl+j.
svelte<script lang="ts">
import { goto } from '$app/navigation'
import { asset, resolve } from '$app/paths'
import type { Pathname } from '$app/types'
import { PageSearch } from 'svelte-widgets'
import { demo_pages } from '../../index'
const resolve_path = resolve as (path: Pathname) => string
const fallback_actions = demo_pages.map((route) => ({
id: route,
label: route,
action: () => goto(resolve_path(route)),
}))
</script>
<PageSearch
{fallback_actions}
navigate={goto}
strip_html_suffix
pagefind_path={asset(`/pagefind/pagefind.js`)}
triggers={[`j`]}
aria_label="Search documentation"
/>
<p>Open the documentation search with <kbd>cmd/ctrl+j</kbd>.</p>The navigate callback receives the selected result’s query, label, and description as its second argument. A persistent layout can carry the query across client-side
navigation and apply highlight_matches to the destination content:
<script lang="ts">
import { afterNavigate, goto } from '$app/navigation'
import { highlight_matches } from 'svelte-widgets/attachments'
import type { PageSearchNavigateDetails } from 'svelte-widgets'
let highlight_query = $state(``)
const navigate = async (url: string, { query }: PageSearchNavigateDetails) => {
await goto(url)
highlight_query = ``
queueMicrotask(() => (highlight_query = query))
}
afterNavigate(() => (highlight_query = ``))
</script>
<main
{@attach highlight_matches({
query: highlight_query,
css_class: `site-search-match`,
duration_ms: 8000,
})}
>
...
</main>
<style>
:global(::highlight(site-search-match)) {
background: gold;
color: inherit;
}
</style>
See the highlight_matches attachments demo for options and effects.
Stemmed Pagefind results may have no exact substring.
Shortcuts, Descriptions & Recent Actions
Actions can carry a description, metadata, badge, keywords, shortcut, and disabled state. The default filter searches all visible fields plus keywords and
supports multiple terms. Shortcuts render as ⌘-style key hints and trigger
globally while the menu is closed unless global_shortcuts={false}. Pass recent_actions_key to persist triggered actions to localStorage and rank them first
when the menu reopens.
Actions require a stable, unique, nonempty string id, including across static actions and loaded pages. Numeric, empty, whitespace-only, and duplicate IDs are rejected. Labels may repeat or change; exact string IDs identify actions and persisted recents. ActionMenu uses the same identity rules.