Model Selector
A device-aware model picker with backend filter chips, vision/tools/cached badges, and download + delete-from-cache affordances.
Model Selector
The Model Selector renders a device-aware list of models grouped by category, with backend filter chips (WebGPU / ONNX / WASM / LiteRT) that show live counts, per-model badges (vision, tool-calling, cached), a download affordance for uncached models, and a delete-from-cache affordance for cached ones. Models that cannot run on the current device — e.g. a WebGPU-only model on a device without WebGPU — are visibly de-emphasized while their "Requires WebGPU" reason stays at full contrast. It emits onSelect(modelId) and owns no selection state.
The backend-filter row wraps at narrow widths and only appears when two or more backends are actually present — a single-backend catalog (e.g. a CLIP embedding pair) hides the row rather than surfacing disabled zero-count chips. The filter chips form a labelled role="group" and expose their pressed state via aria-pressed; the active model row is marked aria-current; the download/delete controls carry aria-labels and expand to a ≥44px touch target on mobile.
Preview
Installation
pnpm dlx shadcn@latest add @localmode/ui/local-first/model-selectornpx shadcn@latest add @localmode/ui/local-first/model-selectoryarn dlx shadcn@latest add @localmode/ui/local-first/model-selectorbunx --bun shadcn@latest add @localmode/ui/local-first/model-selectorData source & dependencies
Data source: renders the model list + hasWebGPU device-fit you pass and emits onSelect(modelId) — works with any backend. Recommended producer: useCapabilities (device-fit) and your useModelRecommendations data from @localmode/react (on-device, optional).
lucide-react— iconsclsx+tailwind-merge— via the sharedcn()util (installed automatically as a registry dependency)
Files installed
model-selector.tsx— theModelSelectorcomponentlib/utils.ts— thecn()helper (if not already present)
Props
ModelSelector
Prop
Type
SelectableModel
Prop
Type
Examples
Bound to recommendations + capabilities
import { useCapabilities } from '@localmode/react';
import { ModelSelector } from '@/components/model-selector';
export function Sidebar({ models, onPick }) {
const { capabilities } = useCapabilities();
return (
<ModelSelector
models={models}
hasWebGPU={Boolean(capabilities?.features.webgpu)}
onSelect={onPick}
onDownload={(id) => prefetch(id)}
onDelete={(id) => evict(id)}
/>
);
}Customization
The de-emphasis (a muted model name, with the amber "Requires WebGPU" reason kept at full — AA — contrast rather than dimmed by opacity) and the hint itself are derived from the hasWebGPU prop — extend isUnfit in the copied file to gate on other backends (e.g. WASM-only). The filter row is auto-hidden for single-backend catalogs (presentBackends.length > 1); drop that guard if you always want the row. Badge icons use lucide-react; the active filter chip uses bg-primary. Styled entirely with shadcn/ui CSS-variable utilities so it inherits your theme — because you own the copied file, every class and threshold is yours to change.
Chrome AI Download Gate
The button a user must click before Chrome will fetch a built-in AI model — plus the in-flight progress and the terminal unsupported / cannot-run states.
Model Loading Panel
A full-height "waiting for model" splash combining metadata, a progress bar, and a first-download-vs-cache-load help message.