# WTabs Controlled tabs widget. Renders a tab list and a content panel. The `selected:` state prefix activates on the currently active tab, so callers can supply tokens like `selected:border-b-2 selected:text-blue-600` through `tabClassName`. This is a fully controlled widget: `selectedIndex` is managed by the caller. ## Table of Contents - [Basic Usage](#basic-usage) - [Props](#props) - [Constructor](#constructor) - [Styling Examples](#styling-examples) - [Related Documentation](#related-documentation) ## Basic Usage ```dart WTabs( tabs: const ['Overview', 'Details', 'Settings'], selectedIndex: _selectedTab, onChanged: (i) => setState(() => _selectedTab = i), listClassName: 'flex flex-row border-b border-gray-200 dark:border-gray-700', tabClassName: ''' px-4 py-2 text-sm text-gray-500 dark:text-gray-400 selected:text-blue-600 dark:selected:text-blue-400 selected:border-b-2 selected:border-blue-600 dark:selected:border-blue-400 ''', panelClassName: 'pt-4', panelBuilder: (index) => _panels[index], ) ``` ## Props | Prop | Type | Default | Description | |:-----|:-----|:--------|:------------| | `tabs` | `List` | **Required** | The labels rendered for each tab, in display order. | | `selectedIndex` | `int` | **Required** | Zero-based index of the currently selected tab. | | `panelBuilder` | `Widget Function(int index)` | **Required** | Returns the panel content for the currently selected tab. | | `onChanged` | `ValueChanged?` | `null` | Called with the tapped tab's index. The caller updates `selectedIndex` in response. | | `listClassName` | `String?` | `null` | Utility classes for the tab-list row container. Example: `'flex flex-row border-b border-gray-200 dark:border-gray-700'`. | | `tabClassName` | `String?` | `null` | Utility classes applied to every tab's inner `WDiv`. Supports `selected:` prefixed tokens: they activate only on the selected tab. | | `selectedTabClassName` | `String?` | `null` | Extra utility classes appended to the active tab's `WDiv` only. Applied after `tabClassName`. | | `panelClassName` | `String?` | `null` | Utility classes for the panel wrapper `WDiv`. Example: `'pt-4'`. | | `fullWidthList` | `bool` | `true` | When true, prepends `w-full` to the tab list so a `border-b` baseline spans the full container width (tabs stay content-sized, left-aligned). If `listClassName` already sets a width token (`w-*`), that width is respected and `w-full` is not prepended, so an explicit width wins. Set `false` for a content-width strip (centered pill tabs). | ## Constructor ```dart WTabs({ Key? key, required List tabs, required int selectedIndex, required Widget Function(int index) panelBuilder, ValueChanged? onChanged, String? listClassName, String? tabClassName, String? selectedTabClassName, String? panelClassName, bool fullWidthList = true, }) ``` ## Styling Examples ### Underline Tabs Classic underline style: `selected:border-b-2` on the active tab. Pair border and text colors with `dark:` variants: ```dart WTabs( tabs: const ['Overview', 'Activity', 'Settings'], selectedIndex: _tab, onChanged: (i) => setState(() => _tab = i), listClassName: 'flex flex-row border-b border-gray-200 dark:border-gray-700', tabClassName: ''' px-4 py-3 text-sm font-medium text-gray-500 dark:text-gray-400 selected:text-rose-600 dark:selected:text-rose-400 selected:border-b-2 selected:border-rose-600 dark:selected:border-rose-400 ''', panelClassName: 'pt-4', panelBuilder: (index) => panels[index], ) ``` ### Pill / Segmented Control Background-based active tab with rounded container: ```dart WTabs( tabs: const ['All', 'Open', 'Resolved'], selectedIndex: _tab, onChanged: (i) => setState(() => _tab = i), listClassName: 'flex flex-row gap-1 p-1 rounded-lg bg-gray-100 dark:bg-gray-800', tabClassName: ''' px-3 py-1.5 rounded-md text-sm font-medium text-gray-600 dark:text-gray-400 selected:bg-white dark:selected:bg-gray-700 selected:text-gray-900 dark:selected:text-white selected:shadow-sm ''', panelClassName: 'pt-4', panelBuilder: (index) => panels[index], ) ``` ### selectedTabClassName for Active-Only Tokens Use `selectedTabClassName` to append active-only classes without `selected:` prefixes: ```dart WTabs( tabs: const ['Profile', 'Security', 'Billing'], selectedIndex: _tab, onChanged: (i) => setState(() => _tab = i), tabClassName: 'px-4 py-2 text-sm text-gray-500 dark:text-gray-400', selectedTabClassName: 'text-blue-600 dark:text-blue-400 border-b-2 border-blue-600 dark:border-blue-400', panelBuilder: (index) => panels[index], ) ``` ## Related Documentation - [WAnchor](./w-anchor.md): each tab is wrapped in a `WAnchor` providing hover and focus state. - [WDiv](./w-div.md): renders the tab list and panel containers. - [WCheckbox](./w-checkbox.md): another controlled widget that drives state prefixes from a prop.