# Select

Import: `import { Select } from '@neo4j-ndl/react'`

## Props

### Select

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `ariaLabel` | `string` |  |  | Aria label of the select component |
| `as` | `ElementType<any, keyof IntrinsicElements>` |  |  | An override of the default HTML tag of the root of the component. Can also be another React component. |
| `errorText` | `ReactNode` |  |  | Error message, if it exists the select will be in error state |
| `helpText` | `ReactNode` |  |  | Help text of the select component |
| `isClean` | `boolean` |  | `false` | Whether the select component is clean. If true, the select component will have a transparent background, no border and be hug the width of the content. |
| `isDisabled` | `boolean` |  |  | Whether the select component is disabled |
| `isFluid` | `boolean` |  | `true` | Whether the select component is fluid |
| `label` | `ReactNode` |  |  | Label of the select component. If not provided, please provide an ariaLabel. |
| `ref` | `any` |  |  | A ref to apply to the root element. |
| `selectProps` | `StateManagerProps<OptionType, IsMulti, GroupType> \| CreatableProps<OptionType, IsMulti, GroupType> \| AsyncProps<...>` |  | `{}` | Props of the select component, based of React Select props |
| `size` | `'large' \| 'medium' \| 'small'` |  | `medium` | Size of the component |
| `type` | `'async' \| 'creatable' \| 'select'` |  | `select` | Type of the select component |

The `type` prop is used to specify the type of select component to render, which will be passed to the underlying React Select component.

The `selectProps` prop is dynamically typed based on the `type` prop and can be one of the following: `StateManagerProps`, `CreatableProps`, `AsyncProps`. All select variants will have the `SelectProps` base type from React Select. For more information on the available props, see the [React Select documentation](https://react-select.com/props).

## Examples

### Default

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { Select } from '@neo4j-ndl/react';

const EXAMPLE_OPTIONS = [
  { label: 'Neo4j', value: 'neo4j' },
  { label: 'Needle 🪡', value: 'needle' },
  { label: 'Graph Databases', value: 'graph-database' },
  {
    label: 'Really long label that does not fit on one row',
    value: 'long-label',
  },
  { isDisabled: true, label: 'Disabled database option', value: 'disabled' },
];

const Component = (props: React.ComponentProps<typeof Select>) => {
  return (
    <Select
      label="Select an option"
      helpText="Help text"
      type="select"
      selectProps={{
        menuIsOpen: props.selectProps?.menuIsOpen,
        options: EXAMPLE_OPTIONS,
      }}
    />
  );
};

export default Component;
```

### Async

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { Select } from '@neo4j-ndl/react';

const EXAMPLE_OPTIONS = [
  { label: 'Neo4j', value: 'neo4j' },
  { label: 'Needle 🪡', value: 'needle' },
  { label: 'Graph Databases', value: 'graph-database' },
  { isDisabled: true, label: 'Disabled database option', value: 'disabled' },
];

const loadOptions = (inputValue: string) => {
  return new Promise<typeof EXAMPLE_OPTIONS>((resolve) => {
    setTimeout(() => {
      const filteredOptions = EXAMPLE_OPTIONS.filter((option) =>
        option.label.toLowerCase().includes(inputValue.toLowerCase()),
      );
      resolve(filteredOptions);
    }, 1000);
  });
};

const Component = (props: React.ComponentProps<typeof Select>) => {
  return (
    <Select
      label="Label"
      helpText="Start typing to load options dynamically"
      type="async"
      selectProps={{
        cacheOptions: true,
        defaultOptions: true,
        isClearable: true,
        loadOptions,
        menuIsOpen: props.selectProps?.menuIsOpen,
        placeholder: 'Type to search...',
      }}
    />
  );
};

export default Component;
```

### Clean

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { Select } from '@neo4j-ndl/react';

const EXAMPLE_OPTIONS = [
  { label: 'Neo4j', value: 'neo4j' },
  { label: 'Needle 🪡', value: 'needle' },
  { label: 'Graph Databases', value: 'graph-database' },
  { isDisabled: true, label: 'Disabled database option', value: 'disabled' },
];

const Component = (props: React.ComponentProps<typeof Select>) => {
  return (
    <Select
      label="Label"
      type="select"
      isClean={true}
      isFluid={false}
      selectProps={{
        menuIsOpen: props.selectProps?.menuIsOpen,
        options: EXAMPLE_OPTIONS,
      }}
    />
  );
};

export default Component;
```

### Controlled

```tsx
import { Select, Typography } from '@neo4j-ndl/react';
import { useState } from 'react';

const EXAMPLE_OPTIONS = [
  { label: 'Neo4j', value: 'neo4j' },
  { label: 'Needle 🪡', value: 'needle' },
  { label: 'Graph Databases', value: 'graph-database' },
  { isDisabled: true, label: 'Disabled database option', value: 'disabled' },
];

const Component = (props: React.ComponentProps<typeof Select>) => {
  const [value, setValue] = useState<(typeof EXAMPLE_OPTIONS)[number]>(
    EXAMPLE_OPTIONS[0],
  );

  return (
    <div className="n-flex n-flex-col n-gap-token-8">
      <Select
        label="Label"
        type="select"
        selectProps={{
          isMulti: false,
          menuIsOpen: props.selectProps?.menuIsOpen,
          menuPortalTarget: document.querySelector('body'),
          onChange: (newValue) => newValue && setValue(newValue),
          options: EXAMPLE_OPTIONS,
          value: value,
        }}
      />
      <Typography variant="body-small">
        Value Selected: {JSON.stringify(value)}
      </Typography>
    </div>
  );
};

export default Component;
```

### Creatable

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { Select } from '@neo4j-ndl/react';

const EXAMPLE_OPTIONS = [
  { label: 'Neo4j', value: 'neo4j' },
  { label: 'Needle 🪡', value: 'needle' },
  { label: 'Graph Databases', value: 'graph-database' },
  { isDisabled: true, label: 'Disabled database option', value: 'disabled' },
];

const Component = (props: React.ComponentProps<typeof Select>) => {
  return (
    <Select
      label="Label"
      helpText="You can create values even if they don't exist as options"
      type="creatable"
      selectProps={{
        isClearable: true,
        menuIsOpen: props.selectProps?.menuIsOpen,
        options: EXAMPLE_OPTIONS,
      }}
    />
  );
};

export default Component;
```

### Custom Label

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { Select } from '@neo4j-ndl/react';
import { QuestionMarkCircleIconOutline } from '@neo4j-ndl/react/icons';

const EXAMPLE_OPTIONS = [
  { label: 'Neo4j', value: 'neo4j' },
  { label: 'Needle 🪡', value: 'needle' },
  { label: 'Graph Databases', value: 'graph-database' },
  { isDisabled: true, label: 'Disabled database option', value: 'disabled' },
];
const Component = (props: React.ComponentProps<typeof Select>) => {
  return (
    <Select
      label={
        <div className="n-flex n-flex-row n-gap-token-4 n-h-7 n-items-center">
          Custom JSX element
          <QuestionMarkCircleIconOutline className="n-h-token-16" />
        </div>
      }
      helpText="You can have a custom label with JSX code 😱"
      type="select"
      selectProps={{
        defaultValue: EXAMPLE_OPTIONS[1],
        menuIsOpen: props.selectProps?.menuIsOpen,
        options: EXAMPLE_OPTIONS,
      }}
    />
  );
};

export default Component;
```

### Disabled

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { Select } from '@neo4j-ndl/react';

const EXAMPLE_OPTIONS = [
  { label: 'Neo4j', value: 'neo4j' },
  { label: 'Needle 🪡', value: 'needle' },
  { label: 'Graph Databases', value: 'graph-database' },
  { isDisabled: true, label: 'Disabled database option', value: 'disabled' },
];

const Component = (props: React.ComponentProps<typeof Select>) => {
  return (
    <Select
      label="Label"
      type="select"
      selectProps={{
        isDisabled: true,
        menuIsOpen: props.selectProps?.menuIsOpen,
        options: EXAMPLE_OPTIONS,
      }}
    />
  );
};

export default Component;
```

### Empty

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { Select } from '@neo4j-ndl/react';

const Component = (props: React.ComponentProps<typeof Select>) => {
  return (
    <Select
      label="Label"
      helpText="Help text"
      type="select"
      selectProps={{
        menuIsOpen: props.selectProps?.menuIsOpen,
        options: [],
      }}
    />
  );
};

export default Component;
```

### Error State

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { Select } from '@neo4j-ndl/react';

const EXAMPLE_OPTIONS = [
  { label: 'Neo4j', value: 'neo4j' },
  { label: 'Needle 🪡', value: 'needle' },
  { label: 'Graph Databases', value: 'graph-database' },
  { isDisabled: true, label: 'Disabled database option', value: 'disabled' },
];

const Component = (props: React.ComponentProps<typeof Select>) => {
  return (
    <Select
      label="Label"
      errorText="Validate that your selection is correct"
      type="select"
      selectProps={{
        menuIsOpen: props.selectProps?.menuIsOpen,
        options: EXAMPLE_OPTIONS,
      }}
    />
  );
};

export default Component;
```

### Inside Dialog

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { Dialog, FilledButton, Select, Typography } from '@neo4j-ndl/react';
import { useRef, useState } from 'react';

const EXAMPLE_OPTIONS = [
  { label: 'Neo4j', value: 'neo4j' },
  { label: 'Needle 🪡', value: 'needle' },
  { label: 'Graph Databases', value: 'graph-database' },
  { isDisabled: true, label: 'Disabled database option', value: 'disabled' },
];

const Component = (props: React.ComponentProps<typeof Select>) => {
  const ref = useRef<HTMLDivElement | null>(null);
  const [isOpen, setIsOpen] = useState<boolean>(false);

  return (
    <div
      ref={ref}
      className="n-flex n-flex-col n-items-center n-justify-center n-relative n-h-[500px]"
    >
      <FilledButton size="medium" onClick={() => setIsOpen(true)}>
        Open Dialog
      </FilledButton>
      <Dialog
        container={ref?.current || undefined}
        isOpen={isOpen}
        onClose={() => setIsOpen(false)}
        aria-label="Dialog"
      >
        <Dialog.Header>Using Select inside a dialog</Dialog.Header>
        <Dialog.Description className="n-flex n-flex-col n-gap-token-32">
          <Typography variant="body-medium">
            To use select inside a dialog and avoid the cut-off, you need to use
            the property <code>menuPosition: &quot;fixed&quot;</code> inside the{' '}
            <code>selectProps</code>. This is done automatically if used in a
            Needle Dialog, but can always be overridden manually.
          </Typography>
          <Select
            label="Inside a dialog"
            type="select"
            selectProps={{
              defaultValue: EXAMPLE_OPTIONS[1],
              menuIsOpen: props.selectProps?.menuIsOpen,
              options: EXAMPLE_OPTIONS,
            }}
          />
        </Dialog.Description>
      </Dialog>
    </div>
  );
};

export default Component;
```

### Menu Positionings

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { Select } from '@neo4j-ndl/react';

const EXAMPLE_OPTIONS = [
  { label: 'Neo4j', value: 'neo4j' },
  { label: 'Needle 🪡', value: 'needle' },
];

const Component = (props: React.ComponentProps<typeof Select>) => {
  return (
    <div className="n-flex n-gap-token-16 n-pt-token-64">
      <Select
        label="Automatic menu placement"
        type="select"
        selectProps={{
          menuIsOpen: props.selectProps?.menuIsOpen,
          menuPlacement: 'auto',
          options: EXAMPLE_OPTIONS,
        }}
      />
      <Select
        label="Bottom menu placement"
        type="select"
        selectProps={{
          menuIsOpen: props.selectProps?.menuIsOpen,
          menuPlacement: 'bottom',
          options: EXAMPLE_OPTIONS,
        }}
      />
      <Select
        label="Top menu placement"
        type="select"
        selectProps={{
          menuIsOpen: props.selectProps?.menuIsOpen,
          menuPlacement: 'top',
          options: EXAMPLE_OPTIONS,
        }}
      />
    </div>
  );
};

export default Component;
```

### Multi

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { Select } from '@neo4j-ndl/react';

const EXAMPLE_OPTIONS = [
  { label: 'Neo4j', value: 'neo4j' },
  { label: 'Needle 🪡', value: 'needle' },
  { label: 'Graph Databases', value: 'graph-database' },
  { isDisabled: true, label: 'Disabled database option', value: 'disabled' },
];

const Component = (props: React.ComponentProps<typeof Select>) => {
  return (
    <Select
      label="Label"
      type="select"
      selectProps={{
        defaultValue: EXAMPLE_OPTIONS[1],
        isClearable: true,
        isMulti: true,
        menuIsOpen: props.selectProps?.menuIsOpen,
        options: EXAMPLE_OPTIONS,
      }}
    />
  );
};

export default Component;
```

### Sizes

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { Select } from '@neo4j-ndl/react';

const EXAMPLE_OPTIONS = [
  { label: 'Neo4j', value: 'neo4j' },
  { label: 'Needle 🪡', value: 'needle' },
  { label: 'Graph Databases', value: 'graph-database' },
  { isDisabled: true, label: 'Disabled database option', value: 'disabled' },
];

const Component = (props: React.ComponentProps<typeof Select>) => {
  return (
    <div className="n-flex n-gap-token-16">
      <Select
        label="Small"
        type="select"
        size="small"
        selectProps={{
          menuIsOpen: props.selectProps?.menuIsOpen,
          options: EXAMPLE_OPTIONS,
        }}
      />
      <Select
        label="Medium"
        type="select"
        size="medium"
        selectProps={{
          menuIsOpen: props.selectProps?.menuIsOpen,
          options: EXAMPLE_OPTIONS,
        }}
      />
      <Select
        label="Large"
        type="select"
        size="large"
        selectProps={{
          menuIsOpen: props.selectProps?.menuIsOpen,
          options: EXAMPLE_OPTIONS,
        }}
      />
    </div>
  );
};

export default Component;
```
