Select

Select component is used to select one or more options from a list of items. We have two different types of select:

  • EnumSelect (used to select one or more options from a list of items)
  • RemoteSelect (used to select one or more options from a list of items fetched from a remote source)

EnumSelect

import { useState } from "react";
import { EnumSelect, useEnumSelectState } from "swash/v2/EnumSelect";

const fruits: Fruit[] = [
  {
    name: "Apple",
    id: 1,
    icon: (
        <div>🍎</div>
    ),
  },
    ...
];

const [value, setValue] = useState<Fruit | null>(null);
const enumSelect = useEnumSelectState({
    value: value,
    onChange: setValue,
    items: fruits,
    title: "Favorite fruit",
    required: false,
    disabledSelector: () => false,
    labelElementSelector: (fruit) => <h3>{fruit.name}</h3>,
    labelSelector: (fruit) => fruit.name,
    valueSelector: (fruit) => fruit.id.toString(),
    appearance: "default",
    emptyMessage: "No fruits",
    footer: <div>
      Ceci est un footer
    </div>
  });

  () => (
    <div className="not-prose">
      <EnumSelect
        state={enumSelect}
        placeholder="Select a fruit..."
        placeholderIcon={
          <div className="flex h-[1em] w-[1em] items-center justify-center">
            🍌
          </div>
        }
        aria-label="Fruits"
        scale="lg"
      />
    </div>
  )

EnumSelectState

To use EnumSelect you have to pass an EnumSelectState object to the component. This object is created using useEnumSelectState hook. In the next part you will learn how to use this hook.

items

items is an array of objects. Each object represents an option in the select. The items should have the following shape:

const items = [
  {
    value: 1,
    label: "Apple",
  },
];

value and label can be replaced by the keywords of your choice, but you will need to adjust valueSelector and labelSelector accordingly.

onChange

onChange is a function that takes an item. This function will be called when the selected values change.

valueSelector

valueSelector is a function that takes an item and returns the value of the item (it needs to be a string). This value will be used to compare the item with the selected value.

labelSelector

labelSelector is a function that takes an item and returns the label of the item (it can be a string or a ReactElement). This label will be used to display options and the selected value.

labelElementSelector (optional)

labelElementSelector is a function that takes an item and returns the label of the item (it can be a string or a ReactElement). This label will be used to display options only.

iconSelector (optional)

iconSelector is a function that takes an item and returns a ReactElement. This icon will be displayed next to the label of the item.

disabledSelector (optional)

disabledSelector is a function that takes an item and returns a boolean. This boolean will be used to disable the item.

required (optional)

required is a boolean that indicates if the select is required or not. If the select is required, the user will not be able to clear the select value.

title (optional)

title is a string that will be used as the label of the select. In some case it will be used as the placeholder of the select.

emptyMessage (optional)

emptyMessage is a string or a ReactElement that will be displayed in the select popover when there are no options is empty.

footer (optional)

footer is a ReactElement that will be displayed in the select popover footer.

appearance (optional)

appearance is a string that indicates the appearance of the select value. It could be default or chip. chip is used to display the selected value as a chip.

EnumSelectState with multiple values

It works the same way as EnumSelectState, but you have to pass an array of values to the value prop.

import { useState } from "react";
import { EnumSelect, useEnumSelectState } from "swash/v2/EnumSelect";

const [value, setValue] = useState<Fruit[]>([]);
const enumSelect = useEnumSelectState({
    value: value,
    onChange: setValue,
    items: fruits,
    title: "Favorite fruit",
    required: false,
    disabledSelector: () => false,
    labelElementSelector: (fruit) => <h3>{fruit.name}</h3>,
    iconSelector: (fruit) => fruit.icon,
    labelSelector: (fruit) => fruit.name,
    valueSelector: (fruit) => fruit.id.toString(),
    appearance: "default",
    emptyMessage: "No fruits"
  });

  () => (
    <div className="not-prose">
      <EnumSelect state={enumSelect} />
    </div>
  )

EnumSelect props

placeholder (optional)

placeholder is a string that will be used as the placeholder of the select.

placeholderIcon (optional)

placeholderIcon is a ReactElement that will be displayed next to the placeholder.

scale (optional)

scale is a string that indicates the scale of the select. It could be sm, md or lg. Default value is md.

Select remote

import { useEffect, useMemo, useState } from "react";
import { RemoteSelect, useRemoteSelectState } from "swash/v2/RemoteSelect";
const fruits: Fruit[] = [
  { id: 1, name: "Apple" },
  { id: 2, name: "Apricot" },
  ...
];
const LIMIT = 10;
const combobox = useComboboxStore();
const search = combobox.useState("search");
const [value, setValue] = useState<Fruit[]>([]);
const [offset, setOffset] = useState<number>(0);
useEffect(() => {
    setOffset(0);
}, [search]);
const data = useMemo(() => {
    const matches = fruits.filter((fruit) =>
    fruit.name.includes(search)
   );
    return {
     items: matches.slice(0, Math.min(offset + LIMIT, matches.length)),
     hasMore: matches.length > offset + LIMIT,
     totalCount: matches.length,
   };
}, [search, offset]);
const enumSelect = useRemoteSelectState({
   value: value,
   onChange: setValue,
   data,
   combobox,
   loading: false,
   fetchMore: (previousData) => {
     setOffset(previousData.items.length);
   },
   getItem: (id) => {
     const fruit = fruits.find((f) => f.id === Number(id));
     if (!fruit) {
       throw new Error(`Fruit not found`);
     }
     return fruit;
   },
   title: "Favorite fruit",
   appearance: "chip",
   labelSelector: (fruit) => fruit.name,
   valueSelector: (fruit) => fruit.id.toString(),
   searchable: true
 });

() => (
   <div className="not-prose">
     <RemoteSelect state={enumSelect} />
   </div>
)

RemoteSelectState

To use RemoteSelect you have to pass an RemoteSelectState object to the component. This object is created using useRemoteSelectState hook. This following props are the same as EnumSelectState props:

  • onChange
  • valueSelector
  • labelSelector
  • labelElementSelector
  • iconSelector
  • disabledSelector
  • required
  • title
  • emptyMessage
  • appearance
  • value

combobox

combobox is a ComboboxStore object. This object is created using useComboboxStore hook.

data

data is an object that should have the following shape:

const data = {
  items: [
    {
      value: 1,
      label: "Apple",
    },
  ],
  totalCount: 1,
  hasMore: 1,
};

items works the same way as EnumSelectState items.

fetchMore

fetchMore is a function that is called when the user scrolls to the bottom of the list. This function should fetch more items and update the data object.

getItem

getItem is a function that takes an id and returns an item. This function is used to get the item from the id when the user selects an item.

searchable (optional)

searchable is a boolean that indicates if the select is searchable or not. Default value is true.

RemoteSelect props

The props are the same as EnumSelect props.