@jagreehal/smart-filters
v1.0.12
Published
AI-powered web component for natural language filter control using Chrome's built-in Browser AI
Downloads
87
Maintainers
Readme
Smart Filters Web Component
Progressive Enhancement: AI features require Chrome 138+ with Prompt API. On unsupported browsers, AI features are disabled but Saved Filters always work - allowing users to save and restore filter configurations.
A reusable web component that scans page filters and sets them via natural language (AI) or saved presets. Uses Chrome's built-in Browser AI (Prompt API) to interpret user queries, with deterministic saved filters that work on any browser.
Features
- Zero-Config - Just add the script and component tag, auto-detects all filters on page
- Saved Filters - Save and restore filter configurations with custom names (works on all browsers)
- Progressive Enhancement - AI features disabled gracefully when unavailable; saved filters always work
- Floating Mode - Unobtrusive FAB that expands to full UI (default for zero-config)
- Bookmarklet Support - Inject into any website via browser bookmark
- Automatic Page Scanning - Detects checkboxes, radio buttons, sliders, dropdowns, and text inputs
- Natural Language Processing - Users describe what they want in plain English (AI-powered)
- Voice Input - Optional speech recognition support (AI-powered)
- Customizable Themes - Multiple color themes (indigo, blue, purple, green, red, slate) + JSON themes
- CSS Parts & Variables - Full styling control via
::part()and CSS custom properties - Content Slots - Inject custom content into predefined locations
- Responsive Container Queries - Automatically adapts to narrow containers
- Variants - Three UI complexity levels: minimal, compact, full
- Flexible Positioning - Floating, fixed corners, or inline
- Multi-language - Built-in support for English, Spanish, French, German, Japanese
- Framework Agnostic - Works with any HTML page, no dependencies
Installation
Option 1: CDN - Auto-Inject (Simplest)
Just include the script from jsDelivr - no element needed:
<script src="https://cdn.jsdelivr.net/npm/@jagreehal/smart-filters/dist/smart-filters-auto.iife.js"></script>Or UNPKG:
<script src="https://unpkg.com/@jagreehal/smart-filters/dist/smart-filters-auto.iife.js"></script>That's it! Automatically injects floating UI and scans the page for filters.
Option 2: CDN - Configurable Element
Add the script and customize with attributes:
<script type="module" src="https://cdn.jsdelivr.net/npm/@jagreehal/smart-filters"></script>
<smart-filters theme="blue" variant="compact"></smart-filters>Same as auto-inject, but gives you control over positioning and attributes.
Option 3: Targeted Container
Point to a specific filter container:
<script type="module" src="dist/smart-filters.js"></script>
<div id="my-filters">
<input type="checkbox" name="wifi" /> Free WiFi
<input type="range" name="price" min="0" max="500" />
</div>
<smart-filters target="my-filters" position="inline"></smart-filters>Option 4: NPM
npm install @jagreehal/smart-filtersimport '@jagreehal/smart-filters';Option 5: Bookmarklet
Inject Smart Filters into any website via bookmarklet:
Create a bookmark with this URL:
javascript:(function(){var s=document.createElement('script');s.src='https://cdn.jsdelivr.net/npm/@jagreehal/smart-filters/dist/smart-filters-bookmarklet.iife.js';document.head.appendChild(s)})();Click the bookmark on any page - click again to toggle visibility.
Build Outputs
| File | Description | Use Case |
|------|-------------|----------|
| smart-filters.js | ES module | Modern bundlers, type="module" |
| smart-filters.umd.cjs | UMD bundle | Legacy bundlers, <script> tag |
| smart-filters-auto.js | ES module auto-inject | Modern auto-inject |
| smart-filters-auto.iife.js | IIFE auto-inject | Universal auto-inject |
| smart-filters-bookmarklet.iife.js | IIFE bookmarklet | Browser bookmark injection |
Usage
Basic Example
<smart-filters target="my-filters"></smart-filters>
<div id="my-filters">
<label>
<input type="checkbox" name="wifi" /> Free WiFi
</label>
<label>
<input type="checkbox" name="parking" /> Parking
</label>
<input type="range" name="price" min="0" max="500" value="250" />
</div>Full-Featured Example
<smart-filters
target="property-filters"
position="inline"
theme="blue"
variant="full"
lang="en"
system-prompt="You are a hotel booking assistant"
storage-key="hotel-demo"
auto-examples
show-saved-filters
show-voice="true"
apply-text="Search"
thinking-text="Searching..."
debounce="500"
width="400px"
></smart-filters>Minimal Variant
<smart-filters
target="filters"
variant="minimal"
theme="slate"
></smart-filters>Attributes
Core Attributes
| Attribute | Type | Default | Description |
|-----------|------|---------|-------------|
| target | string | - | Selector for filter container. If omitted, auto-detects all filters on page |
| position | string | "floating" / "inline" | Position: floating (default when no target), inline (default with target), top-left, top-right, bottom-left, bottom-right |
| theme | string | "slate" | Color theme: slate, indigo, blue, purple, green, red, or JSON object |
| variant | string | "full" | UI complexity: minimal, compact, full |
| lang | string | auto | Language: en, es, fr, de (auto-detects from browser) |
| system-prompt | string | - | Custom AI context/instructions |
| storage-key | string | - | localStorage key for persistence (enables saved filters) |
| auto-examples | boolean | false | AI-generates example queries based on filters |
| show-saved-filters | boolean | false | Show saved filters UI (requires storage-key) |
| show-voice | string | "true" | Show/hide voice input button |
| apply-text | string | - | Custom text for the apply button (overrides locale) |
| thinking-text | string | - | Custom text shown beside spinner during processing |
| debounce | number | - | Auto-submit delay in ms (e.g., "500" triggers after 500ms of inactivity) |
| debug | boolean | false | Show verbose debug info in UI |
| width | string | "auto" | CSS width (e.g., "400px", "100%") |
| z-index | string | "1000" | CSS z-index for fixed positioning |
Data Attributes for Filter Elements
These attributes can be added to your filter inputs for advanced control:
| Attribute | Purpose | Example |
|-----------|---------|---------|
| data-filter-key | Stable key for AI matching (preferred over name/id) | data-filter-key="amenity_wifi" |
| data-format | Format string for range display values | data-format="{value} mi" |
| data-value-map | JSON object mapping values to display labels | data-value-map='{"1":"$","2":"$$","3":"$$$"}' |
| data-for | Associate a display element with an input | data-for="mySlider" |
Example with data attributes:
<input
type="range"
name="distance"
data-filter-key="max_distance"
min="1"
max="25"
value="10"
/>
<span id="distance-value" data-format="{value} miles">10 miles</span>Text Override Attributes
Override any displayed text without changing locale:
| Attribute | Description |
|-----------|-------------|
| title-text | Override title |
| badge-text | Override badge (set to empty string to hide) |
| placeholder-text | Override placeholder |
| description-text | Override description |
| reset-text | Override reset button text |
Icon Customization
| Attribute | Description |
|-----------|-------------|
| icon-url | URL to custom icon image (replaces default SVG) |
Callback Attributes
Specify window function names to call on events:
| Attribute | Description |
|-----------|-------------|
| on-applied | Called when filters applied successfully |
| on-error | Called on error |
| on-loading | Called when processing starts |
| on-ready | Called when component is ready (includes AI availability status) |
| on-reset | Called when filters are reset |
| on-filter-saved | Called when a filter preset is saved |
| on-filter-loaded | Called when a filter preset is loaded |
| on-filter-deleted | Called when a filter preset is deleted |
<smart-filters
target="filters"
on-applied="handleFiltersApplied"
on-error="handleError"
></smart-filters>
<script>
function handleFiltersApplied(detail) {
console.log('Filters applied:', detail.query, detail.actions);
}
function handleError(detail) {
console.error('Error:', detail.error);
}
</script>Events
The component dispatches custom events for integration:
| Event | When | Detail |
|-------|------|--------|
| smartfilters:applied | Filters successfully applied | { query, actions } |
| smartfilters:error | Error occurred | { error, query, rawResponse? } |
| smartfilters:loading | Processing starts | { query } |
| smartfilters:ready | Component ready | { available: boolean } (AI availability) |
| smartfilters:reset | Filters reset | { filters } |
| smartfilters:voicestart | Voice input begins | { active: true } |
| smartfilters:voiceend | Voice input ends | { active: false } |
| smartfilters:filtersaved | Filter preset saved | { id, name, state } |
| smartfilters:filterloaded | Filter preset loaded | { id, name } |
| smartfilters:filterdeleted | Filter preset deleted | { id, name } |
const sf = document.querySelector('smart-filters');
sf.addEventListener('smartfilters:applied', (e) => {
console.log('Query:', e.detail.query);
console.log('Actions:', e.detail.actions);
});
sf.addEventListener('smartfilters:loading', (e) => {
showSpinner();
});
sf.addEventListener('smartfilters:ready', () => {
console.log('AI is ready');
});Public Methods
const sf = document.querySelector('smart-filters');
// Apply a query programmatically
await sf.applyQuery('Show pet-friendly hotels under $200');
// Reset all filters
sf.resetFilters();
// Get current filter values
const state = sf.getFilterState();
// { wifi: true, parking: false, price: '150', ... }
// Set filter values programmatically
sf.setFilterState({ wifi: true, price: '200' });
// Apply actions directly (no AI)
sf.applyActions([
{ key: 'wifi', action: 'check', value: 'true' },
{ key: 'price', action: 'set', value: '200' }
]);
// Saved filters (works without AI)
const saved = sf.getSavedFilters();
// [{ id: 'sf-123', name: 'Beach Hotels', state: {...}, createdAt: 1234567890 }]
// Save current filter state
const filter = sf.saveCurrentFilters('Beach Hotels');
// Load a saved filter by ID
sf.loadSavedFilter('sf-123');
// Delete a saved filter
sf.deleteSavedFilter('sf-123');
// Clear all saved filters
sf.clearSavedFilters();
// Get all detected filters
const filters = sf.getFilters();
// Check if AI is available
if (sf.isAIAvailable) {
// AI features available (query input, auto-examples, voice)
} else {
// Only saved filters work
}Slots
Inject custom content into predefined locations:
<smart-filters target="filters">
<span slot="header-start">
<img src="logo.png" alt="Logo" width="24" />
</span>
<span slot="header-end">
<button>Settings</button>
</span>
<div slot="before-input">
<p>Search tip: Try "pet-friendly under $200"</p>
</div>
<div slot="after-input">
<small>Powered by AI</small>
</div>
<div slot="footer">
<a href="/help">Need help?</a>
</div>
</smart-filters>| Slot Name | Location |
|-----------|----------|
| header-start | Before icon/title in header |
| header-end | After badge, before status |
| before-input | Above input textarea |
| after-input | Below input, above examples |
| footer | After reset button |
CSS Parts
Style component internals using ::part():
smart-filters::part(container) {
border: 2px solid #000;
}
smart-filters::part(button) {
background: #0066cc;
border-radius: 20px;
}
smart-filters::part(input) {
font-size: 16px;
}| Part Name | Element |
|-----------|---------|
| container | Main wrapper (.sf) |
| header | Header row |
| title | Title text |
| badge | AI badge |
| status | Status indicator |
| description | Description text |
| input | Main textarea |
| button | Apply button |
| voice-button | Voice input button |
| examples | Examples container |
| example | Example chip |
| log | Actions log |
| reset | Reset button |
| icon | Custom icon (when using icon-url) |
| row | Input row container |
| fab | Floating action button (floating mode) |
| panel | Expandable panel (floating mode) |
| close | Close button in panel header (floating mode) |
CSS Variables
Typography
smart-filters {
--sf-font: system-ui, sans-serif;
--sf-font-size: 14px;
--sf-font-weight: 400;
--sf-font-weight-medium: 500;
--sf-font-weight-bold: 600;
}Spacing
smart-filters {
--sf-space-xs: 0.25rem;
--sf-space-sm: 0.5rem;
--sf-space-md: 0.75rem;
--sf-space-lg: 1rem;
--sf-space-xl: 1.5rem;
--sf-gap: 0.5rem;
--sf-padding: 1rem;
}Border Radius
smart-filters {
--sf-radius: 0.75rem;
--sf-radius-sm: 0.5rem;
--sf-radius-full: 9999px;
}Shadows
smart-filters {
--sf-shadow: 0 4px 6px -1px rgba(0,0,0,0.1);
--sf-shadow-lg: 0 10px 25px -5px rgba(0,0,0,0.15);
}Colors (Base)
smart-filters {
--sf-bg: #ffffff;
--sf-bg-subtle: #fafafa;
--sf-border: #e5e5e5;
--sf-text: #171717;
--sf-text-muted: #737373;
}Colors (Interactive)
smart-filters {
--sf-primary: #1a56db;
--sf-primary-hover: #1e40af;
--sf-primary-subtle: #f0f4ff;
--sf-primary-border: #e0e7ff;
}Colors (States)
smart-filters {
--sf-success: #22c55e;
--sf-success-subtle: #dcfce7;
--sf-success-border: #86efac;
--sf-success-text: #166534;
--sf-error: #ef4444;
--sf-error-subtle: #fee2e2;
--sf-error-border: #fca5a5;
--sf-error-text: #991b1b;
}Animation
smart-filters {
--sf-duration: 0.15s;
--sf-duration-slow: 1.5s;
--sf-duration-fast: 0.7s;
--sf-easing: ease-out;
}JSON Themes
For complete custom theming, pass a JSON object to the theme attribute:
<smart-filters
target="filters"
theme='{"bg":"#1a1a2e","text":"#eee","primary":"#e94560"}'
></smart-filters>Keys can omit the --sf- prefix. Available keys:
bg,bg-subtle- Backgroundsborder- Border colortext,text-muted- Text colorsprimary,primary-hover,primary-subtle,primary-border- Primary/accent colors
Container Queries
The component automatically adapts to narrow containers:
- < 350px: Hides badge, status text, description. Smaller font sizes.
- < 250px: Hides examples, saved filters. Header wraps.
- > 500px: Button can be side-by-side with input.
This makes the component embeddable in sidebars, modals, and dashboard widgets.
Variants
| Variant | Features | Use Case |
|---------|----------|----------|
| minimal | Icon, title, textarea, link-button only | Clean, Booking.com-style integration |
| compact | Adds badge, examples (no saved filters/description) | Balanced UI |
| full | All features: badge, voice, saved filters, examples, action log | Feature-rich dashboards |
Supported Filter Types
The component automatically detects and supports:
Native HTML Inputs
- Checkboxes -
input[type="checkbox"] - Radio Buttons -
input[type="radio"] - Range Sliders -
input[type="range"] - Number Inputs -
input[type="number"] - Date Inputs -
input[type="date"] - Color Pickers -
input[type="color"] - Select Dropdowns -
<select> - Multi-Select -
<select multiple> - Text Inputs -
input[type="text"],input[type="search"] - Textareas -
<textarea>
ARIA-Based Components (Modern UI Libraries)
Smart Filters automatically detects custom components built with accessible patterns:
- ARIA Checkboxes -
role="checkbox"witharia-checked(Radix UI, shadcn) - ARIA Switches -
role="switch"witharia-checkedordata-state(Headless UI) - ARIA Toggle Buttons -
aria-pressed="true|false"(GitHub, Figma patterns) - ARIA Sliders -
role="slider"witharia-valuemin/max/now(Booking.com, Airbnb) - ARIA Listboxes -
role="listbox"withrole="option"(React Select, Headless UI) - Link Checkboxes - Navigation links styled as checkboxes (Amazon, eBay)
This enables Smart Filters to work seamlessly with:
- Radix UI / shadcn/ui
- Headless UI
- React Aria
- Material-UI / MUI
- Ant Design
- Chakra UI
- Any accessible custom component
Auto-Excluded Elements
The following are automatically excluded from scanning:
- Inputs in
<header>,<nav>, or<footer> - Login and sign-in forms
- Password and email fields
- Hidden inputs
- Search boxes (with
role="search") - Smart Filters' own inputs
Example Queries
Users can type natural language queries like:
- "Pet-friendly hotels under $150 with pool"
- "4+ star rating, free cancellation, breakfast included"
- "Remote jobs paying $100k+ with stock options"
- "Direct flights under $500, morning departure"
Accessibility
Smart Filters is built with accessibility in mind:
Keyboard Navigation
- Tab: Navigate between interactive elements
- Enter/Space: Activate buttons, select examples
- Arrow Up/Down: Navigate saved filters list
- Escape: Close saved filters list, cancel voice input
- Enter (in filter name input): Save current filter
Screen Reader Support
- ARIA live regions announce state changes (loading, success, error, reset)
- Proper ARIA labels on all interactive elements
- Role attributes for semantic structure (
region,listbox,status) - Focus management in dropdown menus
Visual Accessibility
- Focus indicators: Visible 2px outline on all focusable elements
- Reduced motion: Respects
prefers-reduced-motion- disables all animations - High contrast: Full support for Windows High Contrast Mode (
forced-colors) - Increased contrast: Enhanced borders when
prefers-contrast: moreis set - Color independence: Status conveyed through text and shape, not just color
Testing Recommendations
# Test with screen reader
# macOS: VoiceOver (Cmd + F5)
# Windows: NVDA or JAWS
# Test keyboard navigation
# Tab through all elements without mouse
# Test reduced motion
# Enable in system preferences or use browser devtools
# Test high contrast
# Windows: Settings > Ease of Access > High ContrastRequirements
- Chrome 138+ with built-in AI enabled (for AI features)
- Prompt API must be available (for AI features)
- Any modern browser (for saved filters - progressive enhancement)
Browser Compatibility
| Feature | Chrome 138+ | Other Browsers | |---------|-------------|----------------| | Saved Filters | ✅ | ✅ | | AI Query Input | ✅ | ❌ (disabled) | | Voice Input | ✅ | ❌ (hidden) | | Auto-Examples | ✅ | ❌ (hidden) |
The component uses progressive enhancement - saved filters always work, AI features are disabled gracefully when unavailable.
License
MIT License
