search ESC

Searching…

No results for "".

Type at least 2 characters to search.

Docs

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

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

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:

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:

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:

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],
)

  • WAnchor: each tab is wrapped in a WAnchor providing hover and focus state.
  • WDiv: renders the tab list and panel containers.
  • WCheckbox: another controlled widget that drives state prefixes from a prop.