# ComboBox

Die ComboBox kombiniert ein Texteingabefeld mit einem Auswahlmenü. Bei der Eingabe wird eine vordefinierte Liste dynamisch gefiltert, aus der eine Auswahl getroffen werden kann.

## Overview

# Playground

Verwende `<ComboBox />`, um eine ComboBox darzustellen. Nutze ein `<Label />`,
um Informationen zu vermitteln, die das Verständnis der Eingabeanforderungen
erleichtern.

```tsx
import {
  ComboBox,
  Label,
  Option,
} from "@mittwald/flow-react-components";

<ComboBox>
  <Label>Domain</Label>
  <Option>mydomain.de</Option>
  <Option>shop.mydomain.de</Option>
  <Option>anotherdomain.com</Option>
  <Option>www.anotherdomain.com</Option>
  <Option>anotherdomain.com/shop</Option>
  <Option>anotherdomain.com/blog</Option>
  <Option>onemoredomain.de</Option>
  <Option>www.onemoredomain.de</Option>
</ComboBox>
```

---

# Custom Value

Standardmäßig setzt eine ComboBox beim Verlassen des Inputfelds den Eingabewert
entweder auf den Wert der ausgewählten Option zurück oder leert das Feld, wenn
noch keine Option ausgewählt wurde. Mit dem Property `allowsCustomValue` kann
dieses Verhalten überschrieben werden, um auch freie Eingaben zu erlauben.

```tsx
import {
  ComboBox,
  Label,
  Option,
} from "@mittwald/flow-react-components";

<ComboBox allowsCustomValue>
  <Label>Domain</Label>
  <Option>mydomain.de</Option>
  <Option>shop.mydomain.de</Option>
  <Option>anotherdomain.com</Option>
  <Option>www.anotherdomain.com</Option>
  <Option>anotherdomain.com/shop</Option>
  <Option>anotherdomain.com/blog</Option>
  <Option>onemoredomain.de</Option>
  <Option>www.onemoredomain.de</Option>
</ComboBox>
```

---

# Mit FieldDescription

Um wichtige Hinweise zur ComboBox bereitzustellen, kann unterhalb eine
`<FieldDescription />` eingebaut werden.

```tsx
import {
  ComboBox,
  FieldDescription,
  Label,
  Option,
} from "@mittwald/flow-react-components";

<ComboBox>
  <Label>Domain</Label>
  <Option>mydomain.de</Option>
  <Option>shop.mydomain.de</Option>
  <Option>anotherdomain.com</Option>
  <Option>www.anotherdomain.com</Option>
  <Option>anotherdomain.com/shop</Option>
  <Option>anotherdomain.com/blog</Option>
  <Option>onemoredomain.de</Option>
  <Option>www.onemoredomain.de</Option>
  <FieldDescription>Weitere Informationen</FieldDescription>
</ComboBox>
```

---

# Kombiniere mit ...

## Align

Benutze [Align](/04-components/structure/align/overview), um einem
[Button](/04-components/actions/button/overview) neben deiner ComboBox zu
platzieren.

```tsx
import {
  Align,
  Button,
  ComboBox,
  Label,
  Option,
} from "@mittwald/flow-react-components";

<Align>
  <ComboBox>
    <Label>Domain</Label>
    <Option>mydomain.de</Option>
    <Option>shop.mydomain.de</Option>
    <Option>anotherdomain.com</Option>
    <Option>www.anotherdomain.com</Option>
    <Option>anotherdomain.com/shop</Option>
    <Option>anotherdomain.com/blog</Option>
    <Option>onemoredomain.de</Option>
    <Option>www.onemoredomain.de</Option>
  </ComboBox>
  <Button>Hinzufügen</Button>
</Align>
```

## ContextualHelp

Verwende ein [ContextualHelp](/04-components/overlays/contextual-help/overview),
wenn du weitere Informationen bereitstellen möchtest, und diese zu lang für die
FieldDescription sind.

```tsx
import {
  Button,
  ComboBox,
  ContextualHelp,
  ContextualHelpTrigger,
  Heading,
  Label,
  Option,
  Text,
} from "@mittwald/flow-react-components";

<ComboBox>
  <Label>
    Domain
    <ContextualHelpTrigger>
      <Button />
      <ContextualHelp>
        <Heading>Weitere Informationen</Heading>
        <Text>
          Hier gibt es weitere Informationen, die zu lang
          für die FieldDescription sind.
        </Text>
      </ContextualHelp>
    </ContextualHelpTrigger>
  </Label>
  <Option>mydomain.de</Option>
  <Option>shop.mydomain.de</Option>
  <Option>anotherdomain.com</Option>
  <Option>www.anotherdomain.com</Option>
  <Option>anotherdomain.com/shop</Option>
  <Option>anotherdomain.com/blog</Option>
  <Option>onemoredomain.de</Option>
  <Option>www.onemoredomain.de</Option>
</ComboBox>
```

## React Hook Form

Weitere Details zur Formularlogik und -validierung sind in der Component
[Form (React Hook Form)](/04-components/react-hook-form/form/overview) zu
finden.

```tsx
import {
  ComboBox,
  Label,
  Option,
  Section,
} from "@mittwald/flow-react-components";
import { useForm } from "react-hook-form";
import {
  Form,
  SubmitButton,
  typedField,
} from "@mittwald/flow-react-components/react-hook-form";
import { sleep } from "@/content/04-components/actions/action/examples/lib";

export default () => {
  const form = useForm<{ domain: string }>();
  const Field = typedField(form);

  return (
    <Section>
      <Form form={form} onSubmit={sleep}>
        <Field
          name="domain"
          rules={{
            required: "Bitte wähle eine Domain aus",
          }}
        >
          <ComboBox>
            <Label>Domain</Label>
            <Option>mydomain.de</Option>
            <Option>anotherdomain.com</Option>
          </ComboBox>
        </Field>
        <SubmitButton>Speichern</SubmitButton>
      </Form>
    </Section>
  );
}
```

## CountryOptions

Verwende die `CountryOptions` um eine Länderauswahl anzubieten.

```tsx
import {
  ComboBox,
  CountryOptions,
  Label,
} from "@mittwald/flow-react-components";

<ComboBox>
  <Label>Land</Label>
  <CountryOptions />
</ComboBox>
```


## Develop

# Properties

| Property | Type | Default | Description |
| --- | --- | --- | --- |
| `id` | `string` | - | The element's unique identifier. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id). |
| `translate` | `"yes" \| "no"` | - | - |
| `className` | `ClassNameOrFunction<ComboBoxRenderProps>` | `'react-aria-ComboBox'` | The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state. |
| `style` | `StyleOrFunction<TooltipRenderProps>` | - | The inline [style](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style) for the element. A function may be provided to compute the style based on component state. |
| `render` | `DOMRenderFunction<"div", TooltipRenderProps>` | - | Overrides the default DOM element with a custom render function. This allows rendering existing components with built-in styles and behaviors such as router links, animation libraries, and pre-styled components. Requirements: - You must render the expected element type (e.g. if `<button>` is expected, you cannot render an `<a>`). - Only a single root DOM element can be rendered (no fragments). - You must pass through props and ref to the underlying DOM element, merging with your own prop as appropriate. |
| `dir` | `string` | - | - |
| `lang` | `string` | - | - |
| `hidden` | `boolean` | - | - |
| `inert` | `boolean` | - | - |
| `validationBehavior` | `"native" \| "aria"` | `'native'` | Whether to use native HTML form validation to prevent form submission when the value is missing or invalid, or mark the field as required or invalid via ARIA. |
| `isDisabled` | `boolean` | - | Whether the input is disabled. |
| `isReadOnly` | `boolean` | - | Whether the input can be selected but not changed by the user. |
| `isRequired` | `boolean` | - | Whether user input is required on the input before form submission. |
| `isInvalid` | `boolean` | - | Whether the input value is invalid. |
| `validate` | `((value: TimeValue) => true \| ValidationError)` | - | A function that returns an error message if a given value is invalid. Validation errors are displayed to the user when the form is submitted if `validationBehavior="native"`. For realtime validation, use the `isInvalid` prop instead. |
| `autoFocus` | `boolean` | - | Whether the element should receive focus on render. |
| `value` | `TimeValue` | - | The current value (controlled). |
| `defaultValue` | `TimeValue` | - | The default value (uncontrolled). |
| `name` | `string` | - | The name of the input element, used when submitting an HTML form. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefname). |
| `form` | `string` | - | The `<form>` element to associate the input with. The value of this attribute must be the id of a `<form>` in the same document. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input#form). |
| `slot` | `string` | - | A slot name for the component. Slots allow the component to receive props from a parent component. An explicit `null` value indicates that the local props completely override all props received from a parent. |
| `items` | `Iterable<never>` | - | The list of ComboBox items (controlled). |
| `selectedKey` _(deprecated)_ | `Key` | - | The currently selected key in the collection (controlled). @deprecated |
| `defaultSelectedKey` _(deprecated)_ | `Key` | - | The initial selected key in the collection (uncontrolled). @deprecated |
| `disabledKeys` | `Iterable<Key>` | - | The item keys that are disabled. These items cannot be selected, focused, or otherwise interacted with. |
| `selectionMode` | `"single"` | `'single'` | Whether single or multiple selection is enabled. |
| `allowsEmptyCollection` | `boolean` | - | Whether the combo box allows the menu to be open when the collection is empty. |
| `shouldFocusWrap` | `boolean` | - | Whether keyboard navigation is circular. |
| `defaultItems` | `Iterable<never>` | - | The list of ComboBox items (uncontrolled). |
| `inputValue` | `string` | - | The value of the ComboBox input (controlled). |
| `defaultInputValue` | `string` | - | The default value of the ComboBox input (uncontrolled). |
| `allowsCustomValue` | `boolean` | - | Whether the ComboBox allows a non-item matching input value to be set. |
| `menuTrigger` | `MenuTriggerAction` | `'input'` | The interaction required to display the ComboBox menu. |
| `defaultFilter` | `((textValue: string, inputValue: string) => boolean)` | - | The filter function used to determine if a option should be included in the combo box list. |
| `formValue` | `"text" \| "key"` | `'key'` | Whether the text or key of the selected item is submitted as part of an HTML form. When `allowsCustomValue` is `true`, this option does not apply and the text is always submitted. |
| `placeholder` | `string` | - | Temporary text that occupies the text input when it is empty. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/placeholder). |
| `renderEmptyState` | `((props: ListBoxRenderProps) => ReactNode)` | - | Provides content to display when there are no items in the list. |
| `children` | `ReactNode` | - | - |
| `wrapWith` | `ReactElement<unknown, string \| JSXElementConstructor<any>>` | - | - |
| `ref` | `Ref<HTMLSpanElement>` | - | Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref). @see [React Docs](https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom) |
| `key` | `Key` | - | - |

### Events

| Property | Type | Default | Description |
| --- | --- | --- | --- |
| `onChange` | `((value: string) => void)` | - | - |
| `onOpenChange` | `((isOpen: boolean, menuTrigger?: MenuTriggerAction) => void)` | - | Method that is called when the open state of the menu changes. Returns the new open state and the action that caused the opening of the menu. |
| `onClick` | `MouseEventHandler<HTMLDivElement>` | - | - |
| `onClickCapture` | `MouseEventHandler<HTMLDivElement>` | - | - |
| `onAuxClick` | `MouseEventHandler<HTMLDivElement>` | - | - |
| `onAuxClickCapture` | `MouseEventHandler<HTMLDivElement>` | - | - |
| `onContextMenu` | `MouseEventHandler<HTMLDivElement>` | - | - |
| `onContextMenuCapture` | `MouseEventHandler<HTMLDivElement>` | - | - |
| `onDoubleClick` | `MouseEventHandler<HTMLDivElement>` | - | - |
| `onDoubleClickCapture` | `MouseEventHandler<HTMLDivElement>` | - | - |
| `onMouseDown` | `MouseEventHandler<HTMLDivElement>` | - | - |
| `onMouseDownCapture` | `MouseEventHandler<HTMLDivElement>` | - | - |
| `onMouseEnter` | `MouseEventHandler<HTMLDivElement>` | - | - |
| `onMouseLeave` | `MouseEventHandler<HTMLDivElement>` | - | - |
| `onMouseMove` | `MouseEventHandler<HTMLDivElement>` | - | - |
| `onMouseMoveCapture` | `MouseEventHandler<HTMLDivElement>` | - | - |
| `onMouseOut` | `MouseEventHandler<HTMLDivElement>` | - | - |
| `onMouseOutCapture` | `MouseEventHandler<HTMLDivElement>` | - | - |
| `onMouseOver` | `MouseEventHandler<HTMLDivElement>` | - | - |
| `onMouseOverCapture` | `MouseEventHandler<HTMLDivElement>` | - | - |
| `onMouseUp` | `MouseEventHandler<HTMLDivElement>` | - | - |
| `onMouseUpCapture` | `MouseEventHandler<HTMLDivElement>` | - | - |
| `onTouchCancel` | `TouchEventHandler<HTMLDivElement>` | - | - |
| `onTouchCancelCapture` | `TouchEventHandler<HTMLDivElement>` | - | - |
| `onTouchEnd` | `TouchEventHandler<HTMLDivElement>` | - | - |
| `onTouchEndCapture` | `TouchEventHandler<HTMLDivElement>` | - | - |
| `onTouchMove` | `TouchEventHandler<HTMLDivElement>` | - | - |
| `onTouchMoveCapture` | `TouchEventHandler<HTMLDivElement>` | - | - |
| `onTouchStart` | `TouchEventHandler<HTMLDivElement>` | - | - |
| `onTouchStartCapture` | `TouchEventHandler<HTMLDivElement>` | - | - |
| `onPointerDown` | `PointerEventHandler<HTMLDivElement>` | - | - |
| `onPointerDownCapture` | `PointerEventHandler<HTMLDivElement>` | - | - |
| `onPointerMove` | `PointerEventHandler<HTMLDivElement>` | - | - |
| `onPointerMoveCapture` | `PointerEventHandler<HTMLDivElement>` | - | - |
| `onPointerUp` | `PointerEventHandler<HTMLDivElement>` | - | - |
| `onPointerUpCapture` | `PointerEventHandler<HTMLDivElement>` | - | - |
| `onPointerCancel` | `PointerEventHandler<HTMLDivElement>` | - | - |
| `onPointerCancelCapture` | `PointerEventHandler<HTMLDivElement>` | - | - |
| `onPointerEnter` | `PointerEventHandler<HTMLDivElement>` | - | - |
| `onPointerLeave` | `PointerEventHandler<HTMLDivElement>` | - | - |
| `onPointerOver` | `PointerEventHandler<HTMLDivElement>` | - | - |
| `onPointerOverCapture` | `PointerEventHandler<HTMLDivElement>` | - | - |
| `onPointerOut` | `PointerEventHandler<HTMLDivElement>` | - | - |
| `onPointerOutCapture` | `PointerEventHandler<HTMLDivElement>` | - | - |
| `onGotPointerCapture` | `PointerEventHandler<HTMLDivElement>` | - | - |
| `onGotPointerCaptureCapture` | `PointerEventHandler<HTMLDivElement>` | - | - |
| `onLostPointerCapture` | `PointerEventHandler<HTMLDivElement>` | - | - |
| `onLostPointerCaptureCapture` | `PointerEventHandler<HTMLDivElement>` | - | - |
| `onScroll` | `UIEventHandler<HTMLDivElement>` | - | - |
| `onScrollCapture` | `UIEventHandler<HTMLDivElement>` | - | - |
| `onWheel` | `WheelEventHandler<HTMLDivElement>` | - | - |
| `onWheelCapture` | `WheelEventHandler<HTMLDivElement>` | - | - |
| `onAnimationStart` | `AnimationEventHandler<HTMLDivElement>` | - | - |
| `onAnimationStartCapture` | `AnimationEventHandler<HTMLDivElement>` | - | - |
| `onAnimationEnd` | `AnimationEventHandler<HTMLDivElement>` | - | - |
| `onAnimationEndCapture` | `AnimationEventHandler<HTMLDivElement>` | - | - |
| `onAnimationIteration` | `AnimationEventHandler<HTMLDivElement>` | - | - |
| `onAnimationIterationCapture` | `AnimationEventHandler<HTMLDivElement>` | - | - |
| `onTransitionCancel` | `TransitionEventHandler<HTMLDivElement>` | - | - |
| `onTransitionCancelCapture` | `TransitionEventHandler<HTMLDivElement>` | - | - |
| `onTransitionEnd` | `TransitionEventHandler<HTMLDivElement>` | - | - |
| `onTransitionEndCapture` | `TransitionEventHandler<HTMLDivElement>` | - | - |
| `onTransitionRun` | `TransitionEventHandler<HTMLDivElement>` | - | - |
| `onTransitionRunCapture` | `TransitionEventHandler<HTMLDivElement>` | - | - |
| `onTransitionStart` | `TransitionEventHandler<HTMLDivElement>` | - | - |
| `onTransitionStartCapture` | `TransitionEventHandler<HTMLDivElement>` | - | - |
| `onFocus` | `((e: FocusEvent<Element, Element>) => void)` | - | Handler that is called when the element receives focus. |
| `onBlur` | `((e: FocusEvent<Element, Element>) => void)` | - | Handler that is called when the element loses focus. |
| `onFocusChange` | `((isFocused: boolean) => void)` | - | Handler that is called when the element's focus status changes. |
| `onKeyDown` | `((e: KeyboardEvent) => void)` | - | Handler that is called when a key is pressed. |
| `onKeyUp` | `((e: KeyboardEvent) => void)` | - | Handler that is called when a key is released. |
| `onSelectionChange` _(deprecated)_ | `((key: Key) => void)` | - | Handler that is called when the selection changes. @deprecated |
| `onInputChange` | `((value: string) => void)` | - | Handler that is called when the ComboBox input value changes. |

### Accessibility

| Property | Type | Default | Description |
| --- | --- | --- | --- |
| `aria-label` | `string` | - | Defines a string value that labels the current element. |
| `aria-labelledby` | `string` | - | Identifies the element (or elements) that labels the current element. |
| `aria-describedby` | `string` | - | Identifies the element (or elements) that describes the object. |
| `aria-details` | `string` | - | Identifies the element (or elements) that provide a detailed, extended description for the object. |


## Guidelines

# Grundlagen

Die ComboBox kombiniert ein Texteingabefeld mit einem Auswahlmenü. Sie
ermöglicht es Usern, durch die Eingabe von Text Vorschläge aus einer
vordefinierten Liste zu erhalten und daraus eine Auswahl zu treffen. Die Liste
wird bei Texteingabe dynamisch gefiltert. Eine freie Eingabe außerhalb der
vorgeschlagenen Optionen ist nicht vorgesehen.

## Best practices

Achte bei der Verwendung einer ComboBox darauf, dass ...

- die angezeigten Optionen klar und eindeutig benannt sind.
- die Liste der Vorschläge sinnvoll eingegrenzt ist, um die Auswahl zu
  erleichtern.
- die vorgeschlagenen Optionen die erwarteten Eingaben möglichst vollständig
  abdecken.

## Verwendung

Verwende eine Combobox, um ...

- Usern eine gezielte Auswahl aus einer umfangreicheren Liste zu ermöglichen.
- Eingaben zu beschleunigen und Eingabefehler zu minimieren, indem passende
  Optionen vorgeschlagen werden.

## ComboBox vs. Autocomplete

ComboBoxen und
[Autocomplete](/04-components/form-controls/autocomplete/overview) sehen oft
ähnlich aus, erfüllen aber unterschiedliche Zwecke. 

- aus einer vordefinierten Liste von Optionen eine Auswahl zu treffen.
- bei bekannten, überschaubaren Optionen (z. B. Sprachen, Kategorien, Geschlecht).

- Usern zu ermöglichen, freie Eingaben zu machen, während Vorschläge zur Auswahl angezeigt werden. 
- bei langen oder dynamischen Datenlisten (z. B. Städte, Usernamen, Tags).

