Skip to content

Using Viselect with Preact ​

TIP

This is merely a convenience wrapper around the core library. If you want to have full control over it, you can roll out your own wrapper in your app.

Source Code ​

You can find the source code for this component here. You can use it as template for your own implementation.

Installation ​

To use Viselect with Preact, install its preact package with:

sh
$ npm install @viselect/preact
sh
$ pnpm install @viselect/preact
sh
$ yarn add @viselect/preact

Usage ​

You can use Viselect in your Preact project by importing the SelectionArea component from the @viselect/preact package.

TIP

All options are exposed as props. They're a one-to-one mapping of the original options describe here!

NOTE

Changing the props won't do anything as React doesn't deep-compare props. Trigger a re-render by adding and changing the key of the SelectionArea component. See #226.

tsx
import { SelectionArea, SelectionEvent } from '@viselect/preact';
import { FunctionalComponent } from 'preact';
import { useState } from 'preact/hooks';
import './styles.css';

const App: FunctionComponent = () => {
  const [selected, setSelected] = useState<Set<number>>(() => new Set());

  const extractIds = (els: Element[]): number[] =>
    els.map(v => v.getAttribute('data-key'))
      .filter(Boolean)
      .map(Number);

  const onStart = ({event, selection}: SelectionEvent) => {
    if (!event?.ctrlKey && !event?.metaKey) {
      selection.clearSelection();
      setSelected(() => new Set());
    }
  };

  const onMove = ({store: {changed: {added, removed}}}: SelectionEvent) => {
    setSelected(prev => {
      const next = new Set(prev);
      extractIds(added).forEach(id => next.add(id));
      extractIds(removed).forEach(id => next.delete(id));
      return next;
    });
  };

  return (
    <>
      <SelectionArea className="container" 
                     selectionAreaClass="selection-area"
                     onStart={onStart}
                     onMove={onMove}
                     selectables=".selectable">
        {new Array(42).fill(0).map((_, index) => (
          <div className={selected.has(index) ? 'selected selectable' : 'selectable'}
             data-key={index}
             key={index}/>
        ))}
      </SelectionArea>
    </>
  );
}
css
.container {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-evenly;
  border: 1px dashed #4f5276;
  border-radius: 15px;
  padding: 15px;
  margin: 15px 0;
  user-select: none;
}

.container div {
  height: 50px;
  width: 50px;
  margin: 3px;
  background: rgba(66, 68, 90, 0.075);
  border-radius: 10px;
  cursor: pointer;
}

div.selected {
  background: linear-gradient(45deg, #78b2ff, #218ad9);
}

.selection-area {
  background: rgba(46, 115, 252, 0.11);
  border: 1px solid rgba(98, 155, 255, 0.85);
  border-radius: 0.15em;
}

API ​

Props ​

SelectionArea accepts all options from PartialSelectionOptions as optional props, in addition to the standard Preact HTMLAttributes<HTMLDivElement> props.

Selection options ​

PropType
boundariesQuantify<string | HTMLElement>
containerQuantify<string | HTMLElement>
documentDocument
selectablesQuantify<string>
startAreasQuantify<string | HTMLElement>
selectionAreaClassstring
selectionContainerClassstring
behaviourDeepPartial<Behaviour>
featuresDeepPartial<Features>

All selection option props are optional. boundaries defaults to the component's root <div>. When boundaries is provided, the component does not render that wrapper and the supplied element(s) act as the boundaries instead.

Event callbacks ​

PropType
onBeforeStart(event: SelectionEvent) => boolean | void
onBeforeDrag(event: SelectionEvent) => boolean | void
onStart(event: SelectionEvent) => void
onMove(event: SelectionEvent) => void
onStop(event: SelectionEvent) => void

Returning false from onBeforeStart or onBeforeDrag cancels the selection.

Element props ​

The component also accepts standard Preact <div> attributes, including id, className, style, children, ARIA attributes, and event handlers such as onClick.

The option-related types (PartialSelectionOptions, Behaviour, Features, DeepPartial, and Quantify) and SelectionEvent are re-exported from @viselect/preact. See the API reference for their definitions.

Hooks ​

To access the SelectionArea instance, you can use the useSelection hook provided by the @viselect/preact package. The context is provided by the SelectionArea component, so make sure to use it within the component tree where the SelectionArea is rendered. It contains a SelectionArea instance.

tsx
import { useSelection } from '@viselect/preact';

Released under the MIT License.