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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@plantae-tech/plantae-filter

v0.2.3

Published

Customizable and performant dropdown component with search, multi-select, and virtual scrolling for native <select> elements.

Downloads

68

Readme

Plantae Filter

npm Docs

A lightweight JavaScript plugin to transform native <select> elements into custom dropdown components with search, multi-select, and virtual list rendering (Clusterize.js).


Installation

NPM

npm install @plantae-tech/plantae-filter

CDN (UMD)

<script src="https://plantae-tecnologies.github.io/plantae-filter/plantae-filter.umd.js"></script>

CDN (ES Module)

<script type="module" src="https://plantae-tecnologies.github.io/plantae-filter/plantae-filter.es.js"></script>

Usage

1. Using with UMD (CDN + Vanilla JS)

<script src="https://plantae-tecnologies.github.io/plantae-filter/plantae-filter.umd.js"></script>

<select id="mySelect" data-pl-label="Products">
    <optgroup label="Fruits">
        <option value="apple">Apple</option>
        <option value="banana">Banana</option>
    </optgroup>
    <option value="other">Other</option>
</select>

<script>
    const select = document.getElementById('mySelect');
    const pf = new PlantaeFilter(select);

    // API Example
    pf.addOption({ value: 'grape', text: 'Grape', group: 'Fruits' });
    pf.selectOptions(['grape']);
</script>

2. Using with Bundler (Vite, Webpack, Rollup)

import PlantaeFilter from '@plantae-tech/plantae-filter';

const select = document.querySelector('select');
const filter = new PlantaeFilter(select, {
    label: "Products",
    allText: "All",
    emptyText: "Select options",
    groupSelectedLabel: "Selected",
    applyButtonText: "Apply",
    searchPlaceholder: "Search.."
});

// API Example
filter.addOption({ value: 'grape', text: 'Grape', group: 'Fruits' });
filter.selectOptions(['grape']);

3. Initializing select with custom element (example with UMD)

<script src="https://plantae-tecnologies.github.io/plantae-filter/plantae-filter.umd.js"></script>

<plantae-filter label="Products" empty-text="Select..">
    <select id="mySelect">
        <optgroup label="Fruits">
            <option value="apple">Apple</option>
            <option value="banana">Banana</option>
        </optgroup>
        <option value="other">Other</option>
    </select>
</plantae-filter>

<script>
    const pf = document.querySelector('plantae-filter');

    // API Example
    pf.addOption({ value: 'grape', text: 'Grape', group: 'Fruits' });
    pf.selectOptions(['grape']);
</script>

Data Attributes

Attributes must be informed in camelCase when informed by the class constructor.
The data-pl-* attributes are alternatives that can be used inside the <select> element if you prefer to configure it via the native <select>.
If both are provided, the values from <plantae-filter> will take priority.

| Attribute (constructor class) | Description | Example (<plantae-filter>) | Example (<select>) | | --------------------------------------- | ------------------------------------------ | --------------------------------------------------------------- | -------------------------------------------------------------- | | label | Label shown on the filter | label="Products" | data-pl-label="Products" | | allText | Text when all items are selected | all-text="All" | data-pl-all-text="All" | | emptyText | Text when no item is selected | empty-text="Select" | data-pl-empty-text="Select" | | groupSelectedLabel | Label shown on the "Selected" group | group-selected-label="Selected" | data-pl-group-selected-label="Selected" | | applyButtonText | Label shown on the apply button | apply-button-text="Apply" | data-pl-apply-button-text="Apply" | | searchPlaceholder | Placeholder shown on the search input | search-placeholder="Search.." | data-pl-search-placeholder="Search.." | | searchDebounceDelay | Search engine response time | search-debounce-delay="100" | data-pl-search-debounce-delay="100" | | searchEngineMode | Search engine mode ('fuse' or 'fuse-worker') | search-engine-mode="fuse" | data-pl-search-engine-mode="fuse" | | fuseOptions | JSON string with Fuse.js custom options | fuse-options='{"threshold": 0.2, "distance": 100}' | data-pl-fuse-options='{"threshold": 0.2}' | | clusterizeOptions | JSON string with Clusterize.js options | clusterize-options='{"rows_in_block": 25}' | data-pl-clusterize-options='{"no_data_text": "No data"}' |


⚠️ Important Notice for Vite Users

If you are using Vite as your bundler and installing @plantae-tech/plantae-filter via NPM, you MUST configure your vite.config.ts if you are using searchEngineMode='fuse-worker'.

Why?

When the library is configured with searchEngineMode set to 'fuse-worker', it uses import.meta.url combined with ?worker to load a background thread (via Web Worker) for search operations. Vite’s dependency optimizer (optimizeDeps) might break the dynamic new URL() resolution during pre-bundling of node_modules, causing errors like:

The file does not exist at ".../node_modules/.vite/deps/assets/search-worker-xxxxx.js"

Solution: Add this to your vite.config.ts

export default defineConfig({
    optimizeDeps: {
        exclude: ["@plantae-tech/plantae-filter"]
    }
});

Public API

| Method | Description | |-----------------------------|--------------------------------------------------------| | addOption(option) | Add a single option | | addOptions(options) | Add multiple options | | clearSelection() | Deselect all selected options | | deselectOptions(values) | Deselect specific values | | disableOptions(values) | Disable options by value | | enableOptions(values) | Enable options by value | | getAllOptions() | Get all available options | | getSelected() | Get all selected options as objects | | getValue() | Get the values of selected options (array of strings) | | removeAllOptions() | Remove all options | | removeOptions(values) | Remove options by value | | selectOptions(values) | Select multiple values by value | | setValue(values) | Replace all selected options with new values |


Customization

1. Using Bootstrap 5 Theme

You can apply the official Bootstrap 5 theme by including the stylesheet:

<link rel="stylesheet" href="https://plantae-tecnologies.github.io/plantae-filter/theme/bootstrap5-theme.css">

2. Customizing with ::part()

Plantae Filter exposes the following parts for styling via Shadow DOM ::part() selectors:

| Part Name | Description | | ---------------------- | -------------------------------------------------------- | | filter | The clickable filter input area | | filter-text | The text container inside the filter area | | clear-button | The clear (reset) button inside the filter | | counter-filter | The badge with applied itens counter | | dropdown | The dropdown container with the options list | | dropdown-item | A single option (<li>) inside the dropdown | | dropdown-item selected | A selected option inside the dropdown | | dropdown-item focused | The item currently focused via keyboard navigation | | highlight | The <mark> used to highlight search matches | | optgroup | The group label (<li> separator) inside the dropdown | | apply-button | The "Apply" button inside the dropdown footer | | search-input | The search <input> inside the dropdown |

Example usage:

plantae-filter::part(filter) {
    background: #f1f1f1;
    border-radius: 4px;
}

plantae-filter::part(dropdown-item focused) {
    ackground: #e0e0e0;
}

plantae-filter::part(highlight) {
    background: yellow;
}

Feel free to adapt styles to match your design system.

Advanced Features

Custom render Function (Option HTML override)

You can pass a custom render function via the class constructor to control how each option is rendered inside the dropdown.

This function receives an object containing the full OptionItem, including:

  • text (with applied <mark> highlights)
  • value
  • group
  • disabled
  • selected
  • data (custom metadata from data-* attributes)

Example:

new PlantaeFilter(selectElement, {
  render: ({ text, value, selected, data }) => {
    return `
        <div><strong>${text}</strong></div>
        <small>${data?.description ?? 'no description'}</small>
    `;
  }
});

The text field will already contain search highlights (wrapped in <mark part="highlight">), so you don’t need to reapply them manually.


Option data object (metadata from data-*)

You can add data-* attributes to your <option> elements. All of them will be automatically extracted and available inside the data property of each option.

Example:

<option value="1" data-code="A1" data-description="Imported item">Apple</option>

In the render function or API, you'll get:

{
  value: "1",
  text: "Apple",
  data: {
    code: "A1",
    description: "Imported item"
  }
}

You can also include those fields in the search by configuring fuseOptions.keys:

new PlantaeFilter(select, {
  fuseOptions: {
    keys: ['text', 'value', 'data.description', 'data.code'],
    includeMatches: true
  }
});

Browser Support

Plantae Filter leverages modern browser APIs, including the use of Web Workers to offload the search functionality (powered by Fuse.js) to a separate thread, ensuring a smoother experience when filtering large datasets.

Notes:

  • The Web Worker is automatically used for all search operations.
  • As of today, all modern browsers fully support Web Workers (Chrome, Firefox, Edge, Safari, etc.).
  • Internet Explorer and very old browsers do not support Web Workers and are not compatible with this plugin.
  • There is no fallback implementation if Web Workers are not available.

Recommendation:

Ensure your application targets modern browsers or environments that provide full support for Web Workers.


Powered by Plantae Gestão Agrícola