Launcher
Introduction
Section titled “Introduction”The Launcher component provides a powerful command palette for keyboard-driven navigation in your Astro projects. Version 2.0 features an improved semantic structure with proper ARIA patterns: role="switch" for toggles and native anchors for navigation. The component includes full keyboard support via roving tabindex, instant search, and automatic integration with preference toggles from accessible-astro-components.
When to use
Section titled “When to use”Use the Launcher component when you need to:
- Provide keyboard-driven navigation
- Create a command palette (like VS Code’s Cmd/Ctrl+K)
- Allow quick searching through site pages
- Toggle preferences (dark mode, high contrast, reduced motion)
- Provide power users with efficient navigation
- Add a search-style trigger in your header
Key features
Section titled “Key features”- Accessible by default: Semantic HTML with proper ARIA roles (
role="switch"for toggles) - Keyboard navigation: Open with
Cmd/Ctrl + K, navigate with arrow keys (roving tabindex) - Screen reader support: Live region announcements for results
- Quick search: Instant client-side fuzzy search
- Navigation links: Semantic
<a>elements with custom icons - Switch toggles: LED-style indicators with
role="switch" - Preference sync: Automatic sync with
accessible-astro-componentstoggles - Dark mode: Automatic light/dark theming via
light-dark()CSS - Customizable: Extensive styling through CSS custom properties
- i18n ready: All text labels customizable via props
- Zero dependencies: Pure Astro components
- TypeScript: Full type support
Installation
Section titled “Installation”npm install accessible-astro-launcherpnpm add accessible-astro-launcheryarn add accessible-astro-launcherQuick example
Section titled “Quick example”---import { Launcher, LauncherTrigger, LauncherPreferences, LauncherSwitch, LauncherNav, LauncherLink,} from 'accessible-astro-launcher'---
<LauncherTrigger launcherId="site-launcher" />
<Launcher id="site-launcher"> <LauncherPreferences label="Preferences"> <LauncherSwitch label="Dark mode" onAction="toggle-dark-mode" /> <LauncherSwitch label="High contrast" onAction="toggle-high-contrast" /> </LauncherPreferences> <LauncherNav label="Navigation"> <LauncherLink href="/" label="Home" /> <LauncherLink href="/about" label="About" /> <LauncherLink href="/contact" label="Contact" /> </LauncherNav></Launcher>Components
Section titled “Components”The Launcher system consists of six components that work together:
Launcher
Section titled “Launcher”The main dialog component containing the search input and results.
<Launcher id="my-launcher" labels={{ placeholder: "Type to search...", noResults: "No results found", close: "Close" }}> <!-- LauncherPreferences and LauncherNav go here --></Launcher>LauncherTrigger
Section titled “LauncherTrigger”A button that opens the launcher. Can be placed anywhere in your layout.
<!-- Full trigger with placeholder --><LauncherTrigger launcherId="my-launcher" />
<!-- Compact trigger --><LauncherTrigger launcherId="my-launcher" compact />
<!-- Icon only trigger --><LauncherTrigger launcherId="my-launcher" iconOnly />
<!-- With gradient border effect --><LauncherTrigger launcherId="my-launcher" gradientBorder />LauncherPreferences
Section titled “LauncherPreferences”A <fieldset> wrapper with <legend> for grouping switch toggles.
<LauncherPreferences label="Preferences"> <LauncherSwitch label="Dark mode" onAction="toggle-dark-mode" /> <LauncherSwitch label="High contrast" onAction="toggle-high-contrast" /></LauncherPreferences>LauncherSwitch
Section titled “LauncherSwitch”A toggle button with role="switch" and LED indicator for preference controls.
<LauncherSwitch label="Dark mode" onAction="toggle-dark-mode" checked={false} keywords={["theme", "night"]}/>LauncherNav
Section titled “LauncherNav”A <nav> wrapper with heading for grouping navigation links.
<LauncherNav label="Pages" headingLevel={3}> <LauncherLink href="/" label="Home" /> <LauncherLink href="/about" label="About" /></LauncherNav>LauncherLink
Section titled “LauncherLink”A semantic anchor element for navigation within the launcher.
<!-- Basic link --><LauncherLink href="/dashboard" label="Dashboard" />
<!-- With search keywords --><LauncherLink href="/dashboard" label="Dashboard" keywords={["admin", "panel"]}/>
<!-- With custom icon --><LauncherLink href="/settings" label="Settings"> <svg slot="icon" viewBox="0 0 24 24"><!-- icon SVG --></svg></LauncherLink>
<!-- External link --><LauncherLink href="https://github.com" label="GitHub" target="_blank" rel="noopener noreferrer"/>Launcher
Section titled “Launcher”| Prop | Type | Default | Description |
|---|---|---|---|
id | string | Required | Unique identifier (must match launcherId on triggers) |
labels | LauncherLabels | {} | i18n labels object for all UI text |
class | string | '' | Additional CSS classes |
LauncherLabels object
Section titled “LauncherLabels object”| Property | Type | Default | Description |
|---|---|---|---|
placeholder | string | 'Type to search...' | Search input placeholder |
noResults | string | 'No results for "{query}"' | Text shown when no results (use {query} placeholder) |
endOfResults | string | 'End of results' | Text shown at end of results |
resultsCount | string | '{count} results for "{query}"' | Screen reader announcement (use {count} and {query}) |
close | string | 'Close' | Close button label |
clear | string | 'Clear' | Clear button label |
toSelect | string | 'Select' | Hint text for Enter key |
toNavigate | string | 'Navigate' | Hint text for arrow keys |
toClose | string | 'Close' | Hint text for Escape key |
searchHint | string | 'Type to filter...' | Screen reader hint for search |
LauncherTrigger
Section titled “LauncherTrigger”| Prop | Type | Default | Description |
|---|---|---|---|
launcherId | string | Required | ID of the launcher to open |
id | string | undefined | Optional trigger element ID |
placeholder | string | 'Search' | Placeholder text |
shortcutKey | string | 'K' | Keyboard shortcut key to display |
compact | boolean | false | Compact mode without placeholder |
iconOnly | boolean | false | Icon-only mode |
gradientBorder | boolean | false | Animated gradient border effect |
class | string | '' | Additional CSS classes |
LauncherPreferences
Section titled “LauncherPreferences”| Prop | Type | Default | Description |
|---|---|---|---|
label | string | Required | Fieldset legend text |
class | string | '' | Additional CSS classes |
LauncherSwitch
Section titled “LauncherSwitch”| Prop | Type | Default | Description |
|---|---|---|---|
label | string | Required | Display text |
onAction | string | Required | Action identifier |
checked | boolean | false | Initial checked state |
keywords | string[] | [] | Additional search keywords |
typeLabel | string | 'Toggle' | Label for type indicator |
class | string | '' | Additional CSS classes |
LauncherNav
Section titled “LauncherNav”| Prop | Type | Default | Description |
|---|---|---|---|
label | string | Required | Navigation heading text |
headingLevel | 2 | 3 | 4 | 5 | 6 | 3 | Heading level for label |
class | string | '' | Additional CSS classes |
LauncherLink
Section titled “LauncherLink”| Prop | Type | Default | Description |
|---|---|---|---|
label | string | Required | Display text |
href | string | Required | URL to navigate to |
keywords | string[] | [] | Additional search keywords |
typeLabel | string | 'Go to' | Label for type indicator |
class | string | '' | Additional CSS classes |
Slots:
| Slot | Description |
|---|---|
icon | Custom icon for navigation links |
Accessibility
Section titled “Accessibility”Accessibility isn’t an afterthought - it’s built into the core of this component with proper semantic HTML and ARIA patterns.
Keyboard navigation
Section titled “Keyboard navigation”| Key | Action |
|---|---|
Cmd/Ctrl + K | Open launcher |
Arrow Up/Down | Navigate items |
Enter | Select item |
Escape | Close launcher |
Tab | Move between header elements |
You can type at any time while navigating - the caret stays in the search input, so there’s no need to refocus.
Semantic structure
Section titled “Semantic structure”Version 2.0 uses semantic HTML elements with appropriate ARIA:
- Dialog:
<dialog>witharia-modal="true"andaria-labelledby - Search input:
<input type="search">witharia-controlsandaria-activedescendant - Preferences:
<fieldset>with<legend>for grouping - Switches:
<button role="switch">witharia-checkedfor state - Navigation:
<nav>witharia-labelledbyheading - Links: Native
<a>elements within<ul>/<li>structure - Live region:
role="status"for results count announcements
Focus management
Section titled “Focus management”- Focus stays on search input at all times (enabling continuous typing)
aria-activedescendantmanages the active item for screen readers- Arrow keys update the active item without moving DOM focus
- Focus returns to trigger element when launcher closes
- Clear visual indicators on the active item
Visual indicators
Section titled “Visual indicators”- LED-style indicators for switch toggle states
- Hover/focus highlighting on all items
- Visible focus outlines
- Proper color contrast in light and dark modes
Events
Section titled “Events”The Launcher component dispatches custom events that you can listen for:
launcher:action
Section titled “launcher:action”Dispatched when a switch item is activated.
document.addEventListener('launcher:action', (event) => { switch (event.detail.action) { case 'toggle-dark-mode': window.darkMode?.toggle() break case 'toggle-high-contrast': window.highContrast?.toggle() break case 'toggle-reduced-motion': window.reducedMotion?.toggle() break case 'logout': window.location.href = '/logout' break }})launcher:open
Section titled “launcher:open”Dispatched when the launcher opens. Useful for syncing preference states.
document.addEventListener('launcher:open', () => { // Sync preference states when launcher opens console.log('Launcher opened')})Styling
Section titled “Styling”Make the Launcher your own while maintaining its accessibility features.
CSS custom properties
Section titled “CSS custom properties”The Launcher uses CSS custom properties for easy theming:
:root { /* Base theme colors */ --launcher-theme-light: #fff; --launcher-theme-dark: #090b0f;
/* These are auto-generated from theme colors */ --launcher-text-color: /* auto light/dark */; --launcher-subtle-text-color: /* auto light/dark */; --launcher-outer-border-color: /* auto light/dark */; --launcher-inner-border-color: /* auto light/dark */; --launcher-main-body-color: /* auto light/dark */; --launcher-action-bar-color: /* auto light/dark */; --launcher-kbd-color: /* auto light/dark */; --launcher-interaction-color: /* auto light/dark */; --launcher-backdrop-color: rgba(0 0 0 / 0.3);}:root { /* Launcher dialog */ --launcher-width: min(90vw, 650px); --launcher-height: min(60vh, 500px);
/* Trigger button */ --launcher-trigger-width-min: 44px; --launcher-trigger-width-max: 350px; --launcher-trigger-height: 40px; --launcher-trigger-compact-width: 95px; --launcher-trigger-icon-only-size: 44px;}:root { /* Fluid spacing */ --launcher-space-xs: clamp(0.25rem, 0.2283rem + 0.1087vw, 0.3125rem); --launcher-space-sm: clamp(0.5rem, 0.4783rem + 0.1087vw, 0.5625rem); --launcher-space-md: clamp(0.75rem, 0.7065rem + 0.2174vw, 0.875rem); --launcher-space-lg: clamp(1rem, 0.9565rem + 0.2174vw, 1.125rem); --launcher-space-xl: clamp(1.5rem, 1.4348rem + 0.3261vw, 1.6875rem);
/* Border radius */ --launcher-radius-sm: 0.25rem; --launcher-radius-md: 0.5rem; --launcher-radius-lg: 0.75rem;}:root { --launcher-animation-duration: 0.2s; --launcher-animation-timing: cubic-bezier(0.165, 0.84, 0.44, 1);}
/* Animations respect prefers-reduced-motion */@media (prefers-reduced-motion: reduce) { :root { --launcher-animation-duration: 0s; }}Custom theming example
Section titled “Custom theming example”/* Custom purple theme */:root { --launcher-theme-light: #faf5ff; --launcher-theme-dark: #1a0a2e;}
/* Larger launcher */:root { --launcher-width: min(95vw, 800px); --launcher-height: min(70vh, 600px);}Complete example
Section titled “Complete example”Here’s a full implementation showing all features:
---import { Launcher, LauncherTrigger, LauncherPreferences, LauncherSwitch, LauncherNav, LauncherLink,} from 'accessible-astro-launcher'import { DarkMode, HighContrast, ReducedMotion } from 'accessible-astro-components'---
<header> <nav> <a href="/">My Site</a> <LauncherTrigger launcherId="main-launcher" gradientBorder /> <DarkMode /> </nav></header>
<Launcher id="main-launcher" labels={{ placeholder: "Search pages, actions...", noResults: "Nothing found. Try a different search.", }}> <LauncherPreferences label="Preferences"> <LauncherSwitch label="Toggle dark mode" onAction="toggle-dark-mode" /> <LauncherSwitch label="Toggle high contrast" onAction="toggle-high-contrast" /> <LauncherSwitch label="Toggle reduced motion" onAction="toggle-reduced-motion" /> </LauncherPreferences>
<LauncherNav label="Pages"> <LauncherLink href="/" label="Home" keywords={["start", "main"]} /> <LauncherLink href="/about" label="About Us" keywords={["team", "company"]} /> <LauncherLink href="/blog" label="Blog" keywords={["articles", "posts"]} /> <LauncherLink href="/contact" label="Contact" keywords={["email", "form"]} /> </LauncherNav>
<LauncherNav label="Account"> <LauncherLink href="/settings" label="Settings" /> </LauncherNav></Launcher>
<!-- Handle custom actions --><script> document.addEventListener('launcher:action', (event) => { switch (event.detail.action) { case 'toggle-dark-mode': window.darkMode?.toggle() break case 'toggle-high-contrast': window.highContrast?.toggle() break case 'toggle-reduced-motion': window.reducedMotion?.toggle() break } })</script>TypeScript support
Section titled “TypeScript support”The package includes full TypeScript definitions. Import types as needed:
import type { LauncherProps, LauncherTriggerProps, LauncherPreferencesProps, LauncherSwitchProps, LauncherNavProps, LauncherLinkProps, LauncherLabels, LauncherActionEventDetail,} from 'accessible-astro-launcher'Integration with accessible-astro-components
Section titled “Integration with accessible-astro-components”The Launcher automatically syncs with preference toggles from accessible-astro-components:
| Event | Action ID |
|---|---|
darkmode:change | toggle-dark-mode |
highcontrast:change | toggle-high-contrast |
reducemotion:change | toggle-reduced-motion |
When you use these action IDs, the launcher automatically:
- Updates the LED indicator state when preferences change
- Listens for preference change events
- Syncs state when the launcher opens
Migration from v1 to v2
Section titled “Migration from v1 to v2”Component changes
Section titled “Component changes”| v1 Component | v2 Component | Notes |
|---|---|---|
LauncherList | Removed | No longer needed |
LauncherGroup | LauncherPreferences or LauncherNav | Split by semantic purpose |
LauncherItem type="action" | LauncherSwitch | Dedicated switch component |
LauncherItem type="navigation" | LauncherLink | Dedicated link component |
Props changes
Section titled “Props changes”| v1 Prop | v2 Prop | Notes |
|---|---|---|
LauncherItem.type | Removed | Component determines type |
LauncherItem.pressed | LauncherSwitch.checked | Renamed for clarity |
LauncherItem.onAction | LauncherSwitch.onAction | Same on switch |
LauncherItem.href | LauncherLink.href | Same on link |
Migration steps
Section titled “Migration steps”-
Update imports
import { Launcher, LauncherTrigger, LauncherList, LauncherGroup, LauncherItem } from 'accessible-astro-launcher'import { Launcher, LauncherTrigger, LauncherPreferences, LauncherSwitch, LauncherNav, LauncherLink } from 'accessible-astro-launcher' -
Remove LauncherList wrapper
<Launcher id="my-launcher"><LauncherList><!-- content --></LauncherList></Launcher> -
Replace action items with LauncherSwitch
<LauncherGroup label="Preferences"><LauncherItem type="action" label="Dark mode" onAction="toggle-dark-mode" pressed={false} /></LauncherGroup><LauncherPreferences label="Preferences"><LauncherSwitch label="Dark mode" onAction="toggle-dark-mode" checked={false} /></LauncherPreferences> -
Replace navigation items with LauncherLink
<LauncherGroup label="Pages"><LauncherItem type="navigation" label="Home" href="/" /><LauncherItem type="navigation" label="About" href="/about" /></LauncherGroup><LauncherNav label="Pages"><LauncherLink label="Home" href="/" /><LauncherLink label="About" href="/about" /></LauncherNav> -
Update custom icons
<LauncherItem type="navigation" label="Settings" href="/settings"><LauncherLink label="Settings" href="/settings"><svg slot="icon"><!-- icon --></svg></LauncherItem></LauncherLink>
Full before/after example
Section titled “Full before/after example”v1 (Before):
<Launcher id="site-launcher"> <LauncherList> <LauncherGroup label="Preferences"> <LauncherItem type="action" label="Dark mode" onAction="toggle-dark-mode" /> </LauncherGroup> <LauncherGroup label="Navigate"> <LauncherItem type="navigation" label="Home" href="/" /> <LauncherItem type="navigation" label="About" href="/about" /> </LauncherGroup> </LauncherList></Launcher>v2 (After):
<Launcher id="site-launcher"> <LauncherPreferences label="Preferences"> <LauncherSwitch label="Dark mode" onAction="toggle-dark-mode" /> </LauncherPreferences> <LauncherNav label="Navigate"> <LauncherLink label="Home" href="/" /> <LauncherLink label="About" href="/about" /> </LauncherNav></Launcher>Why the changes?
Section titled “Why the changes?”Version 2.0 introduces these changes to improve semantic correctness:
- Better screen reader announcements: Switches are now announced as “switch, on/off” instead of “option”
- Proper ARIA patterns: Uses
role="switch"for toggles, which is the correct pattern for on/off controls - Native elements: Links are now native
<a>elements, improving screen reader navigation - Semantic grouping:
<fieldset>for switches and<nav>for links provide better structure - Clearer API: Component names directly indicate their purpose