Search
The framework ships a small registry for plugging named data sources into a search overlay. The package does NOT ship a UI — overlays (e.g. a global search modal) consume the registry. Sources can be local arrays, fetched JSON, or any async provider.
Result shape
interface Source {
name: string; // unique key (e.g. 'sections')
label?: string; // display name in result groups
icon?: string; // optional Phosphor class for the group header
limit?: number; // max results per source (default 10)
fetch: (query, opts) => Promise<Result[]>;
}
interface Result {
title: string;
subtitle?: string;
href: string;
group?: string;
icon?: string;
}Registering sources
// One-time registration (e.g. in a Pinia store or app setup)
import { useSearch } from "@vanduo-oss/vd3";
const registry = useSearch(); // the process-wide search registry
registry.register({
name: 'sections',
label: 'Documentation Sections',
icon: 'ph-book-open',
limit: 8,
fetch: async (query) => {
const all = await fetch('/data/sections.json').then(r => r.json());
return all
.filter(s => s.title.toLowerCase().includes(query.toLowerCase()))
.slice(0, 8)
.map(s => ({ title: s.title, subtitle: s.section, href: '/docs/' + s.slug }));
}
});
registry.register({
name: 'guides',
label: 'Guides',
fetch: async (query) => { /* … */ }
});Engine wiring
import { ref, onMounted } from 'vue';
import { useSearch } from "@vanduo-oss/vd3";
const root = ref<HTMLElement | null>(null);
useSearch(root);
// Sources are registered app-wide (see src/stores/search.ts). The composable
// just touches the global so it warms up alongside an overlay component.API Reference
| Method | Description |
|---|---|
registry.register(source) | Add a source. Throws on duplicate name, missing name, or missing fetch. |
registry.unregister(name) | Remove a source by name. Returns boolean. |
registry.list() | Returns a frozen array of registered sources. |
registry.query(text, options?) | Runs every source in parallel and resolves to { text, sources[] }. |
Accessibility
- The registry is purely data — accessibility lives in the overlay that consumes it.
- Result lists SHOULD expose
role="listbox"witharia-label; items getrole="option". - Use ↑/↓ for navigation, Enter for selection, Esc to close — consistent with a typical command-palette pattern.
- Abort in-flight queries on input change so stale results don't race.