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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@crasman/multiselect

v1.3.3

Published

Custom UI for HTML select element.

Downloads

54

Readme

multiselect

multiselect is a custom UI for HTML select element. It attaches to a native select element, replaces it visually with an accessible custom UI, and updates changes between the two.

This component been split into two versions: old Multiselect as is, and a slightly updated version called MirrorSelect. Old version is still available to use and works for backwards compatibility for those who wish to still use it.

The key difference with multiselect and mirrorselect is that mirrorselect reflects the changes in native select options as DOM attribute changes. This will trigger eventListeners and such. It will also listen to changes in the native select options, so you can toggle options with something like select.options[n].toggleAttribute('selected') and the change will be updated in the MirrorSelect component. This was something the old MultiSelct didn't do, and was the motivation for this upgrade.

Installation

npm install @crasman/multiselect

Usage

HTML

Nothing fancy, just native HTML.

<label for="makes-select">Valitse merkit</label>

<select id="makes-select" name="makes" multiple required>
  <option value="" hidden>Merkki</option>
  <option value="Alfa Romeo">Alfa Romeo</option>
  <option value="Audi">Audi</option>
  <option value="BMW">BMW</option>
  <option value="Chevrolet">Chevrolet</option>
</select>

JavaScript

Create a new Multiselect instance for each select element to provide a custom UI for. Old MultiSelect:

import { Multiselect } from '@crasman/multiselect';

const settings = { listElement: { size: 12 } };

document.querySelector('select').forEach((select) => {
  new Multiselect(select, settings);
});

OR new MirrorSelect:

import { MirrorSelect } from '@crasman/multiselect';

const settings = { listElement: { size: 12 } };

document.querySelector('select').forEach((select) => {
  new MirrorSelect(select, settings);
});

Customization

Settings

Following settings may be passed to the constructor:

  • containerElement.className (string) - Class name for the container element, that contains all elements belonging to the multiselect. Defaults to "multiselect-container".
  • buttonElement.idPrefix (string) - Prefix for ID of the button element. Defaults to "multiselect".
  • buttonElement.className (string) - Class name for the button element. Defaults to "multiselect-button".
  • buttonElement.placeholderClassName (string) - Additional class name for the button element, to help styling of the button when the "placeholder" text should be shown. Defaults to "placeholder".
  • buttonElement.textContent (string) - Text content of the button element, when no selections are present. Defaults to text content of the first option.
  • buttonElement.showPlaceholder (boolean) - Show original text content of the button above selected options, when any are present. Defaults to true.
  • buttonElement.preventScrollOnFocus (boolean) - Prevent scrolling to button element on focus. Defaults to false.
  • innerContainerElement.className (string) - Class name for the inner container element, that contains the button and list elements. Defaults to "multiselect-inner-container".
  • labelElement.idPrefix (string) - Prefix for ID of the label element. Defaults to "multiselect-label".
  • labelElement.className (string) - Class name for the label element. Defaults to "multiselect-label".
  • labelElement.disabledClassName (string) - Additional class name for the label element, when multiselect is disabled. Defaults to "disabled".
  • listElement.className (string) - Class name for the list element. Defaults to "multiselect-list".
  • listElement.multipleClassName (string) - Additional class name for the list element, when selection type is multiple. Defaults to "multiple".
  • listElement.size (number) - Number of list items to show at once in the scrolling list box. Defaults to 8.
  • listElement.preventScrollOnFocus (boolean) - Prevent scrolling to list element on focus. Defaults to true.
  • listItemElement.idPrefix (string) - Prefix for IDs of the list item elements. Defaults to "multiselect-option".
  • listItemElement.className (string) - Class name for the list item elements. Defaults to "multiselect-option".
  • listItemElement.focusClassName (string) - Additional class name for the list item elements, when one is the active item in navigation, be it through mouseover or keydown event. This should be used instead of CSS :hover selector, to prevent a list item from having hover styles when navigating with keyboard in the list box. Defaults to "focus".
  • listItemElement.selectedClassName (string) - Additional class name for the list item elements, when one has been selected. Defaults to "selected".
  • listItemElement.disabledClassName (string) - Additional class name for the list item elements, when one is disabled. Defaults to "disabled".
  • listGroupElement.className (string) - Class name for the group container elements of list items. Defaults to "multiselect-group".
  • listGroupListElement.className (string) - Class name for the group list elements, which contain the grouped list items. Defaults to "multiselect-group-list".
  • listGroupListElement.disabledClassName (string) - Additional class name for the group list elements, when one is disabled. Defaults to "disabled".

MirrorSelect only settings

  • baseClassName (string) - Optional parameter for rewriting all the className's basenames for the default styles. Defaults to 'multiselect-'. For example baseClassName: 'project-multiselect__' produces class names like 'project-multiselect__group', 'project-multiselect__container', etc...

  • mirrorNative (boolean) - You can turn the native select's mirror feature off, and run this as if it were the old MultiSelect

  • cloneAttributesWhitelist (string[]) - array of strings to select which attributes from native selects options are passed thru to constructed ul / li component. This can be used for example to pass style and dataset options thru, and use those to style individual options

  • setCssProperties (boolean) - Wether or not to set the CSS-variable style properties --item-height and --list-size for the list elements. In some cases this may be unwanted, for example if you wish to set a custom height options for a specific select element. Disabling this prevents individual options from resetting the size vars, which means the values will cascade normally from the CSS inheritance tree.

  • searchable.searchable (boolean) - Determines whether the search functionality is enabled. By default, this is set to false. If this isn't true, none of the rest searchable params matter.

  • searchable.idPrefix (string) - Prefix for the IDs of the search-related elements. Optional, defaults to 'multiselect-search'.

  • searchable.className (string) - Additional class name that can be applied to the search-related elements, allowing for custom styling. Optional, defaults to 'multiselect-search'.

  • searchable.element (string) - Specifies the HTML element type used to create the search functionality container. Optional, the default element type is 'div'.

  • searchable.autocomplete (string) - Specifies the autocomplete attribute for the search input element. Optional, the default autocomplete is 'off'.

  • searchable.selectionClears (boolean) - Wether selecting an option from the list clears the select box. Defaults to false.

  • searchable.enterSelects (boolean) - Wether hitting enter should select an option from the list (if there is only one option). Defaults to false.

  • searchable.autocomplete (string) - The autocomplete on the search input, on or off. Defaults to 'off'.

Search Functionality

The component now seamlessly integrates an optional search functionality. Users can easily filter options by typing into the provided search input, activated by clicking on the input. The user's input is lowercased and scrubbed of special characters and compared against the select's keys and values, which are also normalized. This enhances the user experience, allowing for a more tolerant search that doesn't require precise typing, such as "Über" or "Škoda"; "uber" or "skoda" will find the right options just as well.

CSS

Default styles are provided in the index.scss file. To use them in your project, you may either import the Sass stylesheet and extend and overwrite the styles as you wish, or copy the contents of the file and edit them as needed. To style the elements, you should use the class names specified in the settings.

To use stylesheet with the default prefixes, something like this should suffice:

@import '../../node_modules/@crasman/multiselect/index.scss';

The styles are provided via a mixin called multiselectStyles, which receives the classname prefix as a parameter. This allows you to use the styles with a custom prefix. Default index.scss provides default styles with the prefix 'multiselect-' which the JS uses by default as well.

To import and use multiselect styles with your custom prefix that fits your BEM convention etc., something like this would work:

@use '../../node_modules/@crasman/multiselect/src/multiselectMixin.scss' as msm;
@include msm.multiselectStyles('project-multiselect__');

.project-multiselect {
  &__own {
    /*...*/
  }

  &__BEM {
    /*...*/
  }

  &__modifications {
    /*...*/
  }
}

In this case, also use the same prefix in the JS settings object:

import Multiselect from '@crasman/multiselect';

const settings = {
  listElement: { size: 12 },
  baseClassName: 'project-multiselect__',
};

document.querySelector('select').forEach((select) => {
  new Multiselect(select, settings);
});