BaseUI code on Square UI Pro
The command palette is the most-used surface of the library — 41% of sessions open it at least once — and the current implementation has hit its ceiling: flat action list, no context awareness, and every consumer app forking it to inject custom actions. v2 makes the palette a platform.
Three pillars: a proper fuzzy matcher (typo-tolerant, weighted by recency), per-context ranking (the palette knows whether you are in a table, a form or an editor), and a typed plugin API so apps stop patching internals.
import { definePaletteSource } from '@lndev-ui/palette';
export const deploySource = definePaletteSource({
id: 'deploys',
// Ranked only when the current route matches.
context: (ctx) => ctx.route.startsWith('/deploys'),
actions: async (query) => {
const environments = await fetchEnvironments(query);
return environments.map((env) => ({
id: `deploy-${env.id}`,
label: `Deploy to ${env.name}`,
icon: RocketIcon,
shortcut: env.isProd ? undefined : ['d', env.key],
run: () => deploy(env),
}));
},
});Backspace, peek with Tabactions propEvery app we surveyed rebuilt ranking on top of the palette. If the library ranked by context, we could delete about 400 lines each.— ecosystem scan, July 2026
Ran the recorded corpus against the prototype matcher: top-3 hit rate goes from 81% to 93.4%, and typo tolerance catches 610 of the 640 near-miss queries. The recency boost matters more than I expected — without it we lose 4 points.
corpus: 18,420 queries
top-1 72.1% (+9.8)
top-3 93.4% (+12.4)
p95 3.1ms @ 5k actionsDesign note: context groups need their own headers in the results list, otherwise the ranking looks random to people who do not know why a table action outranks their recent files. Mock attached to the description — the group header carries the context icon.
A11y pass on the prototype: announcements read the group name before the action, which doubles the verbosity. Suggest announcing the group only when it changes — same pattern the combobox rewrite landed in LNUI-388.
Perf rig results on the ranking pipeline PR: 7.2ms p95 at 5,000 actions, 11.8ms at 10,000. We are inside budget at the target size; past 8k we should chunk the scoring pass across frames. Filed the follow-up as a sub-issue.
Plugin API surface is up for review (PR linked). Last open questions before the freeze: error boundaries per source vs global, and whether context() should be sync-only. Weighing in on both in the PR — review by Thursday and we make the cycle.