# certara-select

A flexible, accessible select component that supports single and multi-select modes, search/filtering, async data loading, and creatable options. Designed to be a drop-in replacement for react-select, select2, and Angular mat-select patterns.

## Features

- Single and Multi-select: Toggle between single value and multiple value selection
- Searchable: Built-in filtering with customizable filter functions
- Async Loading: Load options from remote data sources with debouncing
- Creatable: Allow users to create new options on the fly (tagging)
- Grouped Options: Organize options into logical groups
- Form Integration: Works with `<certara-form>` and native form submission
- Keyboard Navigation: Full keyboard support (arrow keys, enter, escape, backspace)
- Accessible: ARIA attributes and proper focus management
- Themeable: CSS custom properties for easy customization

## Usage

### Basic Select

```html
<certara-select id="my-select" placeholder="Select an option..."></certara-select>

<script>
  const select = document.getElementById('my-select');
  select.options = [
    { value: '1', label: 'Option 1' },
    { value: '2', label: 'Option 2' },
    { value: '3', label: 'Option 3' },
  ];
</script>
```

### Multi-Select

```html
<certara-select multiple placeholder="Select multiple..."></certara-select>
```

### Searchable

```html
<certara-select searchable placeholder="Type to search..."></certara-select>
```

### With Grouped Options

```html
<certara-select id="grouped-select"></certara-select>

<script>
  document.getElementById('grouped-select').options = [
    {
      label: 'Group A',
      options: [
        { value: 'a1', label: 'Option A1' },
        { value: 'a2', label: 'Option A2' },
      ],
    },
    {
      label: 'Group B',
      options: [
        { value: 'b1', label: 'Option B1' },
        { value: 'b2', label: 'Option B2' },
      ],
    },
  ];
</script>
```

### Async Loading

```html
<certara-select async searchable placeholder="Type to load options..."></certara-select>

<script>
  document.querySelector('certara-select').addEventListener('certaraLoad', e => {
    fetch(`/api/search?q=${e.detail.query}`)
      .then(res => res.json())
      .then(data => e.detail.callback(data));
  });
</script>
```

### Creatable (Tagging)

```html
<certara-select multiple searchable creatable placeholder="Add tags..."> </certara-select>
```

### Declarative Options

```html
<certara-select placeholder="Select a fruit...">
  <certara-select-option value="apple">Apple</certara-select-option>
  <certara-select-option value="banana">Banana</certara-select-option>
  <certara-select-option value="cherry" disabled>Cherry</certara-select-option>
</certara-select>
```

### With Option Groups (Declarative)

```html
<certara-select placeholder="Select a vehicle...">
  <certara-select-optgroup label="Cars">
    <certara-select-option value="sedan">Sedan</certara-select-option>
    <certara-select-option value="suv">SUV</certara-select-option>
  </certara-select-optgroup>
  <certara-select-optgroup label="Motorcycles">
    <certara-select-option value="cruiser">Cruiser</certara-select-option>
  </certara-select-optgroup>
</certara-select>
```

## React Usage

```tsx
import { CertaraSelect } from '@certara/certara-ui-react';

function MyComponent() {
  const [value, setValue] = useState(null);

  const options = [
    { value: '1', label: 'Option 1' },
    { value: '2', label: 'Option 2' },
  ];

  return <CertaraSelect options={options} value={value} onCertaraChange={e => setValue(e.detail.value)} placeholder="Select..." searchable clearable />;
}
```

## Angular Usage

```typescript
import { Component } from '@angular/core';

@Component({
  template: `
    <certara-select [options]="options" [value]="selectedValue" (certaraChange)="onSelectionChange($event)" placeholder="Select..." searchable clearable> </certara-select>
  `,
})
export class MyComponent {
  options = [
    { value: '1', label: 'Option 1' },
    { value: '2', label: 'Option 2' },
  ];
  selectedValue = null;

  onSelectionChange(event: CustomEvent) {
    this.selectedValue = event.detail.value;
  }
}
```

## Migration from react-select

| react-select prop   | certara-select equivalent              |
| ------------------- | -------------------------------------- |
| `options`           | `options`                              |
| `value`             | `value`                                |
| `onChange`          | `certaraChange` event                  |
| `isMulti`           | `multiple`                             |
| `isSearchable`      | `searchable`                           |
| `isClearable`       | `clearable`                            |
| `isDisabled`        | `disabled`                             |
| `isLoading`         | `loading`                              |
| `placeholder`       | `placeholder`                          |
| `closeMenuOnSelect` | `closeOnSelect`                        |
| `getOptionLabel`    | Use `labelField` or pre-format options |
| `getOptionValue`    | Use `valueField` or pre-format options |
| `filterOption`      | `filterFn`                             |

## Migration from select2

| select2 option       | certara-select equivalent     |
| -------------------- | ----------------------------- |
| `data`               | `options`                     |
| `multiple`           | `multiple`                    |
| `placeholder`        | `placeholder`                 |
| `allowClear`         | `clearable`                   |
| `disabled`           | `disabled`                    |
| `minimumInputLength` | `minSearchChars`              |
| `ajax`               | `async` + `certaraLoad` event |
| `tags`               | `creatable`                   |
| `templateResult`     | Custom render via slots       |

## Migration from mat-select (Angular Material)

| mat-select feature | certara-select equivalent                      |
| ------------------ | ---------------------------------------------- |
| `[(value)]`        | `value` + `certaraChange`                      |
| `[multiple]`       | `multiple`                                     |
| `[disabled]`       | `disabled`                                     |
| `[placeholder]`    | `placeholder`                                  |
| `<mat-option>`     | `<certara-select-option>` or `options` prop    |
| `<mat-optgroup>`   | `<certara-select-optgroup>` or grouped options |
| `[compareWith]`    | Pre-format options to use consistent values    |

<!-- Auto Generated Below -->


## Overview

A flexible select component supporting single/multi-select, search, async loading,
and creatable options. Compatible with react-select, select2, and mat-select patterns.

## Properties

| Property           | Attribute            | Description                                                                                                                                                                       | Type                                                                   | Default          |
| ------------------ | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | ---------------- |
| `ariaLabel`        | `aria-label`         | Accessible label for the select (use when not inside a form-group)                                                                                                                | `string`                                                               | `null`           |
| `async`            | `async`              | Enable async loading mode                                                                                                                                                         | `boolean`                                                              | `false`          |
| `asyncConfig`      | --                   | Async configuration options                                                                                                                                                       | `SelectAsyncConfig`                                                    | `undefined`      |
| `clearable`        | `clearable`          | Allow clearing the selection                                                                                                                                                      | `boolean`                                                              | `true`           |
| `closeOnSelect`    | `close-on-select`    | Close menu after selecting (default: true for single, false for multi)                                                                                                            | `boolean`                                                              | `undefined`      |
| `creatable`        | `creatable`          | Allow creating new options                                                                                                                                                        | `boolean`                                                              | `false`          |
| `creatableConfig`  | --                   | Creatable configuration options                                                                                                                                                   | `SelectCreatableConfig`                                                | `undefined`      |
| `defaultValue`     | `default-value`      | Default value to restore on form reset                                                                                                                                            | `(string \| number)[] \| number \| string`                             | `null`           |
| `disabled`         | `disabled`           | Whether the control is disabled                                                                                                                                                   | `boolean`                                                              | `false`          |
| `error`            | `error`              | Error message to display                                                                                                                                                          | `string`                                                               | `''`             |
| `filterFn`         | --                   | Custom filter function                                                                                                                                                            | `(option: SelectOption<unknown>, query: string) => boolean`            | `undefined`      |
| `labelField`       | `label-field`        | Label field name if options are objects                                                                                                                                           | `string`                                                               | `'label'`        |
| `loading`          | `loading`            | Show a loading indicator                                                                                                                                                          | `boolean`                                                              | `false`          |
| `maxMenuHeight`    | `max-menu-height`    | Maximum height of dropdown menu in pixels                                                                                                                                         | `number`                                                               | `300`            |
| `menuPortalTarget` | `menu-portal-target` | Renders the dropdown menu into another DOM node. Selects the HTML element using its id. If the id can't be found, defaults to the body.                                           | `boolean \| string`                                                    | `undefined`      |
| `menuWidth`        | `menu-width`         | Maximum width of the dropdown menu in pixels. Use this to allow the menu to be wider than the trigger. The minimum width is the width of the trigger.                             | `number`                                                               | `undefined`      |
| `minSearchChars`   | `min-search-chars`   | Minimum characters before filtering                                                                                                                                               | `number`                                                               | `0`              |
| `multiple`         | `multiple`           | Enable multiple selection mode                                                                                                                                                    | `boolean`                                                              | `false`          |
| `name`             | `name`               | The name of the control for form submission                                                                                                                                       | `string`                                                               | `''`             |
| `options`          | --                   | Options array - can be flat or grouped                                                                                                                                            | `SelectOption<unknown>[] \| SelectOptionGroup<unknown>[]`              | `[]`             |
| `placeholder`      | `placeholder`        | Placeholder text when no option is selected                                                                                                                                       | `string`                                                               | `'Select...'`    |
| `placement`        | `placement`          | Preferred dropdown placement                                                                                                                                                      | `"auto" \| "bottom-end" \| "bottom-start" \| "top-end" \| "top-start"` | `'bottom-start'` |
| `readonly`         | `readonly`           | Whether the control is read-only                                                                                                                                                  | `boolean`                                                              | `false`          |
| `renderOptionHtml` | --                   | Custom render function for option HTML. This function should return a valid HTML string that will be injected into the select option. NOTE: this MUST be a plain string, not JSX. | `(option: SelectOption<unknown>) => string`                            | `undefined`      |
| `required`         | `required`           | Whether the control is required for form validation                                                                                                                               | `boolean`                                                              | `false`          |
| `searchable`       | `searchable`         | Enable search/filtering                                                                                                                                                           | `boolean`                                                              | `false`          |
| `size`             | `size`               | Size variant of the control                                                                                                                                                       | `"lg" \| "md" \| "sm"`                                                 | `'md'`           |
| `value`            | `value`              | Current selected value(s)                                                                                                                                                         | `(string \| number)[] \| number \| string`                             | `null`           |
| `valueField`       | `value-field`        | Value field name if options are objects                                                                                                                                           | `string`                                                               | `'value'`        |
| `variant`          | `variant`            | Visual variant of the control                                                                                                                                                     | `"default" \| "link"`                                                  | `'default'`      |


## Events

| Event                     | Description                                 | Type                                                                                    |
| ------------------------- | ------------------------------------------- | --------------------------------------------------------------------------------------- |
| `certaraBlur`             | Emitted on blur                             | `CustomEvent<FocusEvent>`                                                               |
| `certaraChange`           | Emitted when the value changes              | `CustomEvent<SelectChangeEventDetail<unknown>>`                                         |
| `certaraClose`            | Emitted when the dropdown closes            | `CustomEvent<void>`                                                                     |
| `certaraCreate`           | Emitted when a new option is created        | `CustomEvent<{ value: string; option: SelectOption<unknown>; }>`                        |
| `certaraFocus`            | Emitted on focus                            | `CustomEvent<FocusEvent>`                                                               |
| `certaraFormControlError` | Emitted for form control errors             | `CustomEvent<string>`                                                                   |
| `certaraLoad`             | Emitted when async options should be loaded | `CustomEvent<{ query: string; callback: (options: SelectOption<unknown>[]) => void; }>` |
| `certaraOpen`             | Emitted when the dropdown opens             | `CustomEvent<void>`                                                                     |
| `certaraSearch`           | Emitted when the search query changes       | `CustomEvent<{ query: string; }>`                                                       |


## Methods

### `addOption(option: SelectOption) => Promise<void>`

Adds an option to the list

#### Parameters

| Name     | Type                    | Description |
| -------- | ----------------------- | ----------- |
| `option` | `SelectOption<unknown>` |             |

#### Returns

Type: `Promise<void>`



### `clear() => Promise<void>`

Clears the current selection

#### Returns

Type: `Promise<void>`



### `close() => Promise<void>`

Closes the dropdown menu

#### Returns

Type: `Promise<void>`



### `open() => Promise<void>`

Opens the dropdown menu

#### Returns

Type: `Promise<void>`



### `removeOption(value: string | number) => Promise<void>`

Removes an option from the list

#### Parameters

| Name    | Type               | Description |
| ------- | ------------------ | ----------- |
| `value` | `string \| number` |             |

#### Returns

Type: `Promise<void>`



### `setBlur() => Promise<void>`

Removes focus from the control

#### Returns

Type: `Promise<void>`



### `setFocus() => Promise<void>`

Sets focus to the control

#### Returns

Type: `Promise<void>`



### `setValue(value: SelectValue) => Promise<void>`

Sets the value programmatically

#### Parameters

| Name    | Type                                       | Description |
| ------- | ------------------------------------------ | ----------- |
| `value` | `string \| number \| (string \| number)[]` |             |

#### Returns

Type: `Promise<void>`




## Slots

| Slot           | Description                                                                             |
| -------------- | --------------------------------------------------------------------------------------- |
|                | Default slot for declarative certara-select-option and certara-select-optgroup elements |
| `"no-options"` | Custom content when no options are available                                            |
| `"prefix"`     | Content to show before the selected value (e.g., an icon)                               |


## Dependencies

### Depends on

- [certara-chip](../chip)
- [certara-loader](../loading)
- [certara-select-option](select-option)
- [certara-icon](../icon)

### Graph
```mermaid
graph TD;
  certara-select --> certara-chip
  certara-select --> certara-loader
  certara-select --> certara-select-option
  certara-select --> certara-icon
  certara-chip --> certara-icon
  style certara-select fill:#f9f,stroke:#333,stroke-width:4px
```

----------------------------------------------


