npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@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

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-filters
import '@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 - Backgrounds
  • border - Border color
  • text, text-muted - Text colors
  • primary, 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" with aria-checked (Radix UI, shadcn)
  • ARIA Switches - role="switch" with aria-checked or data-state (Headless UI)
  • ARIA Toggle Buttons - aria-pressed="true|false" (GitHub, Figma patterns)
  • ARIA Sliders - role="slider" with aria-valuemin/max/now (Booking.com, Airbnb)
  • ARIA Listboxes - role="listbox" with role="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: more is 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 Contrast

Requirements

  • 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