# Autocomplete

Autocomplete ergänzt eine Texteingabe um kontextbezogene Vorschläge.

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

export default () => {
  const [input, setInput] = useState("");

  const generateSuggestItems = () => {
    return [
      "example.com",
      "test.org",
      "email.net",
      "mail.com",
    ]
      .map((d) => {
        const email = `${input.split("@")[0]}@${d}`;
        return (
          <Option
            key={email}
            value={email}
            textValue={email}
          >
            {email}
          </Option>
        );
      })
      .filter(() => input);
  };

  return (
    <Autocomplete>
      <TextField value={input} onChange={setInput}>
        <Label>Email</Label>
      </TextField>
      {generateSuggestItems()}
    </Autocomplete>
  );
}
```

---

# Best Practices

- Zeige kontextbezogene Vorschläge an.
- Filtere die Vorschlagsliste bei Bedarf sinnvoll vor. Das kann zum Beispiel
  nach Kategorien oder Kontext erfolgen.
- Zeige bei leerem Eingabefeld zunächst keine Vorschläge an.

## Autocomplete vs. ComboBox

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

- 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).

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

---

# Benutzerdefinierte Filter

Schränke die Optionen, die dem User zur Auswahl stehen, mithilfe von Filtern
ein.

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

export default () => {
  const [input, setInput] = useState("");

  const generateSuggestItems = () => {
    return [
      "example.com",
      "test.org",
      "email.net",
      "mail.com",
    ]
      .map((d) => {
        const email = `${input.split("@")[0]}@${d}`;
        return (
          <Option
            key={email}
            value={email}
            textValue={email}
          >
            {email}
          </Option>
        );
      })
      .filter(() => input);
  };

  const domainDotComFilter = (
    textValue: string,
    ignored_inputValue: string,
  ) => {
    return textValue.includes(".com");
  };

  return (
    <Autocomplete filter={domainDotComFilter}>
      <TextField value={input} onChange={setInput}>
        <Label>Email</Label>
      </TextField>
      {generateSuggestItems()}
    </Autocomplete>
  );
}
```

---

# Kombiniere mit ...

## SearchField

Nutze `<Autocomplete />` mit einem
[SearchField](/04-components/form-controls/search-field), um die User beim
Suchen mit Vorschlägen zu unterstützen.

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

export default () => {
  const [input, setInput] = useState("");

  const components = [
    "Button",
    "Checkbox",
    "ContextMenu",
    "Modal",
    "Select",
    "TextField",
  ];

  const suggestItems = components
    .filter((name) =>
      name.toLowerCase().includes(input.toLowerCase()),
    )
    .map((name) => (
      <Option key={name} value={name} textValue={name}>
        {name}
      </Option>
    ))
    .filter(() => input);

  return (
    <Autocomplete>
      <SearchField value={input} onChange={setInput}>
        <Label>Komponente</Label>
      </SearchField>
      {suggestItems}
    </Autocomplete>
  );
}
```

## React Hook Form

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

```tsx
import {
  Label,
  Autocomplete,
  Section,
  TextField,
  Option,
} from "@mittwald/flow-react-components";
import { useForm, useWatch } 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<{ email: string }>({
    defaultValues: {
      email: "",
    },
  });
  const Field = typedField(form);

  const currentEmailValue = useWatch({
    name: "email",
    control: form.control,
  });

  const generateSuggestItems = () => {
    return [
      "example.com",
      "test.org",
      "email.net",
      "mail.com",
    ]
      .map((d) => {
        const email = `${currentEmailValue.split("@")[0]}@${d}`;
        return (
          <Option
            key={email}
            value={email}
            textValue={email}
          >
            {email}
          </Option>
        );
      })
      .filter(() => currentEmailValue);
  };

  return (
    <Section>
      <Form form={form} onSubmit={sleep}>
        <Field
          name="email"
          rules={{
            required: "Bitte wähle eine App aus",
          }}
        >
          <Autocomplete>
            <TextField>
              <Label>Test</Label>
            </TextField>
            {generateSuggestItems()}
          </Autocomplete>
        </Field>
        <SubmitButton>Speichern</SubmitButton>
      </Form>
    </Section>
  );
}
```

---

# Properties

| Property | Type | Default | Description |
| --- | --- | --- | --- |
| `children` | `ReactNode` | - | - |
| `className` | `string` | - | The elements class name. |
| `wrapWith` | `ReactElement<unknown, string \| JSXElementConstructor<any>>` | - | A React element the component is wrapped with. The element is cloned and receives the component as its only child — useful to render the component inside a link, a tooltip trigger or any other wrapper without changing the surrounding markup. |
| `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` | - | - |
| `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. |
| `filter` | `((textValue: string, inputValue: string, node: Node<object>) => boolean)` | - | An optional filter function used to determine if a option should be included in the autocomplete list. Include this if the items you are providing to your wrapped collection aren't filtered by default. |
| `disableAutoFocusFirst` | `boolean` | `false` | Whether or not to focus the first item in the collection after a filter is performed. Note this is only applicable if virtual focus behavior is not turned off via `disableVirtualFocus`. |
| `disableVirtualFocus` | `boolean` | `false` | Whether the autocomplete should disable virtual focus, instead making the wrapped collection directly tabbable. |

