Select

Composable select control.

Single value

import { x } from "@xstyled/styled-components";
import { useState } from "react";
import {
  Select,
  SelectDisclosure,
  SelectMenu,
  SelectOption,
  SelectPlaceholder,
  SelectValue,
  useSelectState,
} from "swash/Select";

const options = [
  { label: "A - Option A", value: "A" },
  { label: "B - Option B", value: "B" },
  { label: "C - Option C", value: "C" },
  { label: "D - Option D", value: "D" },
  { label: "E - Option E", value: "E" },
  { label: "F - Option F", value: "F" },
  { label: "G - Option G", value: "G" },
  { label: "H - Option H", value: "H" },
  { label: "I - Option I", value: "I" },
];

function Example() {
  const [value, setValue] = useState(null);
  const select = useSelectState({ value, onChange: setValue });
  return (
    <Select {...select}>
      <SelectDisclosure {...select}>
        <SelectValue {...select} />
        <SelectPlaceholder {...select}>Indice</SelectPlaceholder>
      </SelectDisclosure>
      <SelectMenu {...select} aria-label="Indice">
        {options.map((option) => (
          <SelectOption key={option.value} {...select} value={option.value}>
            {option.label}
          </SelectOption>
        ))}
      </SelectMenu>
    </Select>
  );
}

render(<Example />);

Single searchable value

import { x } from "@xstyled/styled-components";
import { useState } from "react";
import {
  Select,
  SelectCaret,
  SelectClearButton,
  SelectDisclosure,
  SelectMenu,
  SelectOption,
  SelectPlaceholder,
  SelectSearch,
  SelectValue,
  useSelectState,
} from "swash/Select";

const options = [
  { label: "A - Option A", value: "A" },
  { label: "B - Option B", value: "B" },
  { label: "C - Option C", value: "C" },
  { label: "D - Option D", value: "D" },
  { label: "E - Option E", value: "E" },
  { label: "F - Option F", value: "F" },
  { label: "G - Option G", value: "G" },
  { label: "H - Option H", value: "H" },
  { label: "I - Option I", value: "I" },
];

function Example() {
  const [value, setValue] = useState(null);
  const select = useSelectState({
    value,
    onChange: setValue,
    searchable: true,
  });
  return (
    <Select {...select}>
      <SelectDisclosure {...select}>
        <SelectValue {...select} />
        <SelectSearch {...select} placeholder="Indice" />
        <SelectCaret {...select} />
        <SelectClearButton {...select} />
      </SelectDisclosure>
      <SelectMenu {...select} aria-label="Indice">
        {options
          .filter((option) => option.label.includes(select.state.search.value))
          .map((option) => (
            <SelectOption key={option.value} {...select} value={option.value}>
              {option.label}
            </SelectOption>
          ))}
      </SelectMenu>
    </Select>
  );
}

render(<Example />);

Single searchable value with custom footer

import { x } from "@xstyled/styled-components";
import { useState } from "react";
import {
  Select,
  SelectCaret,
  SelectClearButton,
  SelectDisclosure,
  SelectMenu,
  SelectMenuFooter,
  SelectOption,
  SelectPlaceholder,
  SelectSearch,
  SelectValue,
  useSelectState,
} from "swash/Select";
import { Radio, RadioGroup, RadioLabel } from "swash/controls/Radio";

const options = [
  { label: "A - Option A", value: "A" },
  { label: "B - Option B", value: "B" },
  { label: "C - Option C", value: "C" },
];

const FooterOptions = () => {
  const [values, setValues] = useState({
    radio1: false,
    radio2: false,
    radio3: false,
  });
  return (
    <SelectMenuFooter>
      <RadioGroup>
        <RadioLabel data-scale="sm">
          <Radio
            onChange={(event) =>
              setValues({ ...values, radio1: event.target.checked })
            }
            checked={values.radio1}
          />
          Smaller
        </RadioLabel>
        <RadioLabel>
          <Radio
            onChange={(event) =>
              setValues({ ...values, radio2: event.target.checked })
            }
            checked={values.radio2}
          />
          Default
        </RadioLabel>
        <RadioLabel data-scale="lg">
          <Radio
            onChange={(event) =>
              setValues({ ...values, radio3: event.target.checked })
            }
            checked={values.radio3}
          />
          Bigger
        </RadioLabel>
      </RadioGroup>
    </SelectMenuFooter>
  );
};

function Example() {
  const [value, setValue] = useState(null);
  const select = useSelectState({
    value,
    onChange: setValue,
    searchable: true,
  });

  return (
    <Select {...select}>
      <SelectDisclosure {...select}>
        <SelectValue {...select} />
        <SelectSearch {...select} placeholder="Indice" />
        <SelectCaret {...select} />
        <SelectClearButton {...select} />
      </SelectDisclosure>
      <SelectMenu {...select} aria-label="Indice" footer={<FooterOptions />}>
        {options
          .filter((option) => option.label.includes(select.state.search.value))
          .map((option) => (
            <SelectOption key={option.value} {...select} value={option.value}>
              {option.label}
            </SelectOption>
          ))}
      </SelectMenu>
    </Select>
  );
}

render(<Example />);