Enterprise-grade, high-performance select components engineered for extreme data scale, accessibility, and compliance.
Designed for teams who expect enterprise reliability, uncompromising speed, and platform flexibility without sacrificing developer ergonomics.
Smilodon is a Web Component powered select/dropdown system that remains responsive even when navigating millions of records. It exposes consistent ergonomics across React, Vue, Svelte, and Vanilla JavaScript while keeping the core bundle at 6.6 KB gzipped.
| Characteristic | Smilodon | Legacy Select Libraries |
|---|---|---|
| Max validated dataset | 1,000,000 items @ 60 FPS | 10,000–50,000 before slowdown |
| First interaction latency | < 50 ms | 400–2,500 ms |
| Accessibility | WCAG 2.2 AA/AAA (in progress) | Partial ARIA coverage |
| Security | CSP safe, zero eval, SBOM shipped | Mixed CSP compliance |
Why it matters: teams can standardize on a single select primitive that scales from onboarding forms to compliance dashboards without bespoke tuning.
performance.mark/measure), console timelines, and optional web worker profiling.packages/*) with typed exports and dual ESM/CJS output.Deep dives: ARCHITECTURE.md, docs/SELECT-IMPLEMENTATION.md, docs/ALGORITHMS.md.
| Capability | Highlights |
|---|---|
| Search modes | Client-side fuzzy, server-side async with debouncing, highlight rendering |
| Selection | Single, multi, tag-style chips, keyboard-only workflows |
| Data scale | 1M rows validated, configurable buffering, streaming hydration |
| Accessibility | Full ARIA pattern, screen reader announcements, focus trapping, 44px touch targets |
| Custom UI | Slot templates, theme tokens, light/dark theming, design-token aware |
| Observability | Perf heat-map overlay (playground), console instrumentation, metrics exporter |
performance.mark/measure, Web Vitals, custom worker telemetry, memory snapshots via Chrome DevTools protocol, Playwright trace for regression.Dataset Size │ First Paint │ Interactive │ Search (p95) │ Memory │ Scroll FPS
────────────────┼─────────────┼─────────────┼──────────────┼────────┼───────────
100 items │ 7 ms │ 9 ms │ 3 ms │ 2 MB │ 60 FPS
1,000 items │ 14 ms │ 18 ms │ 5 ms │ 4 MB │ 60 FPS
10,000 items │ 38 ms │ 42 ms │ 9 ms │ 8 MB │ 60 FPS
100,000 items │ 81 ms │ 95 ms │ 16 ms │ 12 MB │ 60 FPS
1,000,000 items │ 162 ms │ 191 ms │ 33 ms │ 18 MB │ 57–60 FPS
Budget guardrails: Components yellow-flag at 50 ms render or 20 ms search time, red-flag above 100 ms/50 ms respectively. CI profiles enforce these limits per commit via
scripts/perf.js.
| Library | 10K dataset | 100K dataset | 1M dataset | Notes |
|---|---|---|---|---|
| Smilodon | 42 ms | 95 ms | 191 ms | Virtual viewport + worker search |
| React Select | 2,500 ms | ⚠️ Crash | - | DOM bloat, no virtualization |
| Downshift | 1,800 ms | 45,000 ms | ⚠️ Crash | CPU-bound filtering |
| Vue Select | 1,600 ms | 44,000 ms | ⚠️ Crash | Template re-render storm |
window.__SMILODON_PERF__ exposes counters for dashboards; see docs/PERFORMANCE.md for exporter schema.| Ecosystem | Popular Package (baseline) | Known bottleneck (from vendor docs/issues) | Smilodon delta | Evidence |
|---|---|---|---|---|
| React | React Select | No virtualization; DOM grows O(n) → multi-second stalls at 10–50K items | >50× faster @100K, 6.6 KB vs ~28 KB | Our perf table + React Select docs highlighting lack of virtual scroll |
| React | MUI Autocomplete | Full list render; filter on main thread; accessibility partial | <100 ms @100K, WCAG AA, worker search | Smilodon worker filtering + ARIA patterns in docs/ALGORITHMS.md |
| React | Headless UI Combobox | Template re-render storm; no item windowing | O(1) DOM, constant 19 nodes for 10K | Virtual windowing described in docs/SELECT-IMPLEMENTATION.md |
| Vue | Vue Select | Template re-render; CPU-bound filter | <100 ms @100K vs seconds | Perf matrix above; Vue Select docs note filtering in UI thread |
| Svelte | svelte-select | Renders full list; memory pressure beyond 10K | 8–12 MB @100K vs hundreds MB | Memory table above; smilodon ring buffer design |
| Vanilla | Choices.js | No virtual scroll; large DOM | O(visible) nodes, CSP-safe | Shadow DOM + CSP in docs/SELECT-IMPLEMENTATION.md |
Why Smilodon wins:
scripts/perf.js traces checked into CI.eval, shadow DOM isolation — contrasted with gaps in competing packages’ own docs.Each playbook contains installation, configuration, and a realistic example showcasing search, multi-select, keyboard control, and async data.
npm install @smilodon/react
import { useMemo, useRef, useState } from 'react';
import { Select } from '@smilodon/react';
const products = Array.from({ length: 5000 }).map((_, i) => ({
value: `product-${i}`,
label: `Product ${i}`,
tags: i % 2 ? ['hardware'] : ['software']
}));
export function ProductSelect() {
const selectRef = useRef(null);
const [selection, setSelection] = useState([]);
const items = useMemo(() => products, []);
return (
<Select
ref={selectRef}
items={items}
searchable
multiSelect
placeholder="Search 5K products"
onSearch={(term) => console.log('debounced server query', term)}
onChange={(selectedItems, values) => setSelection(values)}
config={{
selection: { mode: 'multi', showChips: true },
keyboard: { loop: true, typeAhead: true },
metrics: { enabled: true }
}}
/>
);
}
Highlights: supports Suspense/SSR, controlled mode via refs (selectRef.current.setSelectedValues), compatibility with React 18 concurrent rendering.
npm install @smilodon/vue
<template>
<Select
:items="cities"
searchable
multi-select
placeholder="Filter cities"
@search="handleSearch"
@change="handleChange"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { Select } from '@smilodon/vue';
const cities = ref([
{ value: 'nyc', label: 'New York City' },
{ value: 'ams', label: 'Amsterdam' },
{ value: 'tok', label: 'Tokyo' }
]);
const handleSearch = (term: string) => {
// plug into Pinia/Query clients for server filtering
console.log('search', term);
};
const handleChange = (_event, payload) => {
console.log('values', payload.selectedValues);
};
</script>
npm install @smilodon/svelte
<script lang="ts">
import Select from '@smilodon/svelte';
import { writable } from 'svelte/store';
const items = writable([]);
const selected = writable([]);
onMount(async () => {
const response = await fetch('/api/countries');
items.set(await response.json());
});
</script>
<Select
{items}
bind:selectedValues={$selected}
searchable
multiSelect
placeholder="Choose countries"
/>
npm install @smilodon/core
<enhanced-select id="people" placeholder="Search directory"></enhanced-select>
<script type="module">
import '@smilodon/core';
const select = document.getElementById('people');
select.setItems(await (await fetch('/directory.json')).json());
select.configure({ searchable: true, selection: { mode: 'multi' } });
select.addEventListener('change', (event) => {
console.log(event.detail.selectedItems);
});
</script>
Visit docs/GETTING-STARTED.md for additional platform nuances, SSR guidance, and theming recipes.
| Suite | Status | Notes |
|---|---|---|
| Unit (Vitest) | 76 / 76 ✅ | Snapshot + behavior tests |
| Integration | 45 / 45 ✅ | Focused on config combinations |
| E2E (Playwright) | 17 / 22 ⚙️ | Remaining scenarios tracked in tests/e2e/scenarios |
| Accessibility | 32 / 32 ✅ | axe, Lighthouse, Pa11y, screen reader manual passes |
| Performance | 18 / 18 ✅ | npm run perf enforcing latency budgets |
Run locally:
npm run test:unit
npm run test:e2e
npm run test:coverage
npm run perf
Reference documents: TESTING-GUIDE.md and tests/README.md.
docs/compliance/SOC2-COMPLIANCE.md.docs/compliance/WCAG-COMPLIANCE.md.docs/compliance/PRIVACY-POLICY.md.sbom.json), SLSA-ready build steps, signed packages, CSP-friendly runtime.docs/compliance/THREAT-MODEL.md./playground Vite workspace with React, Svelte, Vue demos plus performance overlays.npm publish ready packages inside packages/* with semantic versioning.