# Tabs

Tabs strukturieren verwandte Inhalte und ermöglichen einen schnellen Zugriff auf unterschiedliche Ansichten.

## Overview

# Playground

Verwende `<Tabs />`, um Tabs darzustellen. Jeder einzelne Tab wird mit `<Tab />`
definiert und erhält seine Bezeichnung über `<TabTitle />`.

```tsx
import {
  Header,
  Heading,
  Label,
  LabeledValue,
  LayoutCard,
  Section,
  Switch,
  Tab,
  Tabs,
  TabTitle,
  Text,
  TextField,
} from "@mittwald/flow-react-components";

<LayoutCard>
  <Tabs>
    <Tab>
      <TabTitle>Allgemein</TabTitle>
      <Section>
        <Heading>Allgemein</Heading>
        <TextField defaultValue="example@mittwald.de">
          <Label>E-Mail-Adresse</Label>
        </TextField>
      </Section>
    </Tab>
    <Tab id="storage">
      <TabTitle>Speicherplatz</TabTitle>
      <Section>
        <Heading>Speicherplatz</Heading>
        <LabeledValue>
          <Label>Verfügbarer Speicherplatz</Label>
          <Text>2.4 GB</Text>
        </LabeledValue>
      </Section>
    </Tab>
    <Tab>
      <TabTitle>Spamschutz</TabTitle>
      <Section>
        <Header>
          <Heading>Spamschutz</Heading>
          <Switch>Spamfilter</Switch>
        </Header>
        <Text>
          Der Spamfilter schützt dich vor ungewollten
          E-Mails. Niemand will Müll in seinem Postfach,
          daher empfehlen wir den Spamschutz immer aktiviert
          zu lassen.
        </Text>
      </Section>
    </Tab>
  </Tabs>
</LayoutCard>
```

---

# Kollabierte Ansicht

Wenn die verfügbare Breite nicht ausreicht, wechseln die Tabs automatisch in
eine kollabierte Ansicht.

```tsx
import {
  LayoutCard,
  Tab,
  Tabs,
  TabTitle,
} from "@mittwald/flow-react-components";

<LayoutCard style={{ width: "250px" }}>
  <Tabs>
    <Tab>
      <TabTitle>Allgemein</TabTitle>
      Allgemeiner Inhalt
    </Tab>
    <Tab id="storage">
      <TabTitle>Speicherplatz</TabTitle>
      Speicherplatz Inhalt
    </Tab>
    <Tab>
      <TabTitle>Spamschutz</TabTitle>
      Spamschutz Inhalt
    </Tab>
  </Tabs>
</LayoutCard>
```

---

# Mit Status-Icon

Wenn der Inhalt eines Tabs eine wichtige Information oder Warnung enthält (z. B.
in Form eines [Alerts](/04-components/status/alert/overview)), muss der
entsprechende Tab ein Status-Icon erhalten.

```tsx
import {
  Alert,
  AlertIcon,
  Heading,
  LayoutCard,
  Tab,
  Tabs,
  TabTitle,
} from "@mittwald/flow-react-components";

<LayoutCard>
  <Tabs>
    <Tab>
      <TabTitle>Allgemein</TabTitle>
      Allgemeiner Inhalt
    </Tab>
    <Tab id="storage">
      <TabTitle>
        Speicherplatz
        <AlertIcon status="danger" />
      </TabTitle>
      <Alert status="danger">
        <Heading>Dein Speicherplatz ist voll</Heading>
      </Alert>
    </Tab>
    <Tab>
      <TabTitle>Spamschutz</TabTitle>
      Spamschutz Inhalt
    </Tab>
  </Tabs>
</LayoutCard>
```

---

# Mit vorausgewähltem Tab

Standardmäßig sollte der erste Tab vorausgewählt sein. Falls ein anderer Tab
initial aktiv sein soll, kann dies über `defaultSelectedKey` festgelegt werden.

```tsx
import {
  LayoutCard,
  Tab,
  Tabs,
  TabTitle,
} from "@mittwald/flow-react-components";

<LayoutCard>
  <Tabs defaultSelectedKey="storage">
    <Tab>
      <TabTitle>Allgemein</TabTitle>
      Allgemeiner Inhalt
    </Tab>
    <Tab id="storage">
      <TabTitle>Speicherplatz</TabTitle>
      Speicherplatz Inhalt
    </Tab>
    <Tab>
      <TabTitle>Spamschutz</TabTitle>
      Spamschutz Inhalt
    </Tab>
  </Tabs>
</LayoutCard>
```


## Develop

# Reihenfolge der Tabs

Es kann vorkommen, dass sich durch Rerendering die Reihenfolge der Tabs ändert,
wenn innerhalb des Tabs Inhalte nachgeladen werden. Um das zu verhindern, sollte
der Tab-Inhalt in eine eigene Komponente ausgelagert werden und um diese ein
Suspense gelegt werden.

```
<Tabs>
  <Tab>
    <TabTitle>Tab 1</TabTitle>
    <Suspense>
      <Tab1Content/>
    </Suspense>
  </Tab>
  <Tab>
    <TabTitle>Tab 2</TabTitle>
    <Suspense>
      <Tab2Content/>
    </Suspense>
  </Tab>
</Tabs>
```

---

# Properties

| Property | Type | Default | Description |
| --- | --- | --- | --- |
| `tabNotFoundView` | `ReactNode` | - | - |
| `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<TabsRenderProps>` | `'react-aria-Tabs'` | 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` | - | - |
| `isDisabled` | `boolean` | - | Whether the TabList is disabled. Shows that a selection exists, but is not available in that circumstance. |
| `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. |
| `selectedKey` | `Key` | - | The currently selected key in the collection (controlled). |
| `defaultSelectedKey` | `Key` | - | The initial selected keys in the collection (uncontrolled). |
| `keyboardActivation` | `"manual" \| "automatic"` | `'automatic'` | Whether tabs are activated automatically on focus or manually. |
| `orientation` | `Orientation` | `'horizontal'` | The orientation of the tabs. |
| `disabledKeys` | `Iterable<Key>` | - | The item keys that are disabled. These items cannot be selected, focused, or otherwise interacted with. |
| `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 |
| --- | --- | --- | --- |
| `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>` | - | - |
| `onSelectionChange` | `((key: Key) => void)` | - | Handler that is called when the selection 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

## Best practices

Achte bei der Verwendung von Tabs darauf, dass ...

- innerhalb eines Tabs nur thematisch eng verwandter Content gruppiert wird.
- nie mehrere Tabs gleichzeitig relevant für eine Aufgabe sind. Alle relevanten
  Informationen müssen innerhalb eines Tabs direkt zugänglich sein.
- idealerweise nicht mehr als sechs Tabs verwendet werden, um Übersichtlichkeit
  zu gewährleisten.
- die Reihenfolge nach Wichtigkeit oder Häufigkeit der Nutzung erfolgt.
- jeder Tab eigenständig verständlich ist und eine kurze und deutliche
  Beschriftung hat.
- kein Content in mehreren Tabs gedoppelt wird.
- sie keine Hauptnavigation ersetzen.
- sie oberhalb von einer
  [LayoutCard](/04-components/structure/layout-card/overview) positioniert
  werden.
- bei Statusanzeigen innerhalb eines Tabs – z. B. durch einen
  Danger-[Alert](/04-components/status/alert/overview) – der Tab selbst ein
  entsprechendes Status-Icon erhält, um die Aufmerksamkeit darauf zu lenken.

## Verwendung

Verwende Tabs, um ...

- komplexe Inhalte in kleinere, übersichtlichere Ansichten zu gliedern.
- umfangreiche Detailseiten in mehrere aufgaben- oder themenbezogene Abschnitte
  aufzuteilen.

