Tabs
Ported from HyperUI’s Tabs — see Attribution. hyperui’s own static gallery
capture for this pattern component type shows one representative pose
(first tab already active — see docs/agents/parity-pipeline.md’s hazard
legend) — no interactive tab-switching to port, same convention as
toggles/checkboxes.
Includes a dark: variant — toggle the site theme (top right) to preview it.
class Tabs1Example extends StatelessWidget { const Tabs1Example({super.key});
@override Widget build(BuildContext context) { return Style( 'mx-auto max-w-3xl p-6', children: [ Style( '-mb-px border-b border-gray-200 dark:border-gray-700', child: Style( 'flex gap-1', children: const [ Style( 'border-b-2 border-blue-600 px-4 py-2 text-sm font-medium text-blue-600 transition-colors hover:text-blue-700 dark:hover:text-blue-500', child: Text('Profile'), ), Style( 'border-b-2 border-transparent px-4 py-2 text-sm font-medium text-gray-600 transition-colors hover:text-gray-700 dark:text-gray-300 dark:hover:text-gray-200', child: Text('Account'), ), Style( 'border-b-2 border-transparent px-4 py-2 text-sm font-medium text-gray-600 transition-colors hover:text-gray-700 dark:text-gray-300 dark:hover:text-gray-200', child: Text('Notifications'), ), ], ), ), const Style( 'mt-4', child: Style( 'text-gray-700 dark:text-gray-200', child: Text( 'Lorem, ipsum dolor sit amet consectetur adipisicing elit. Deserunt similique, quae hic dicta ' 'quo facere facilis praesentium a sunt, est quia pariatur nam, modi aut minus iste odio ' 'consectetur molestias iusto cupiditate ullam laborum veniam quos officia. Quos, temporibus ' 'perspiciatis!', ), ), ), ], ); }}Original HTML not vendored yet for this variant — run npm run vendor-original-html -- <category>/<slug>.
With icons
Section titled “With icons”Includes a dark: variant — toggle the site theme (top right) to preview it.
class CurrentColorIcon extends StatelessWidget implements StyleReplacedElementWrapper { const CurrentColorIcon(this.svg, {super.key});
final String svg;
@override Widget build(BuildContext context) { final color = IconTheme.of(context).color ?? const Color(0xFF000000); return SvgPicture.string(svg, theme: SvgTheme(currentColor: color)); }}
const _profileSvg = '''<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M15.75 6a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0zM4.501 20.118a7.5 7.5 0 1114.998 0A17.933 17.933 0 0112 21.75c-2.676 0-5.216-.584-7.499-1.632z"/></svg>''';
const _settingsSvg = '''<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.041.147.083.22.127.324.196.72.257 1.076.124l1.217-.456a1.125 1.125 0 011.37.49l.772 1.341a1.125 1.125 0 01-.12 1.386l-.949.823c-.254.243-.373.645-.206 1.008.084.258.116.52.116.785 0 .26-.032.52-.116.785-.167.363-.048.765.206 1.008l.949.823a1.125 1.125 0 01.12 1.386l-.772 1.341a1.125 1.125 0 01-1.37.49l-1.217-.456c-.356-.133-.75-.072-1.076.124a6.47 6.47 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 1.281c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.369-.49l-.772-1.341a1.125 1.125 0 01.12-1.386l.949-.823c.253-.243.373-.645.206-1.008a6.591 6.591 0 01-.116-.785c0-.26.032-.52.116-.785.167-.363.048-.765-.206-1.008l-.949-.823a1.125 1.125 0 01-.12-1.386l.772-1.341a1.125 1.125 0 011.37-.49l1.217.456c.356.133.751.072 1.076-.124.072-.044.145-.087.22-.128.332-.183.582-.495.644-.869l.213-1.281z"/><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/></svg>''';
const _alertsSvg = '''<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"/></svg>''';
class Tabs2Example extends StatelessWidget { const Tabs2Example({super.key});
@override Widget build(BuildContext context) { return Style( 'mx-auto max-w-3xl p-6', children: [ Style( 'border-b border-gray-200 dark:border-gray-700', child: Style( '-mb-px flex gap-4', children: [ Style( 'flex items-center gap-2 border-b-2 border-blue-600 px-4 py-2 text-sm font-medium text-blue-600 transition-colors hover:text-blue-700 dark:hover:text-blue-500', children: const [ Style('size-4', child: CurrentColorIcon(_profileSvg)), Text('Profile'), ], ), Style( 'flex items-center gap-2 border-b-2 border-transparent px-4 py-2 text-sm font-medium text-gray-600 transition-colors hover:text-gray-700 dark:text-gray-300 dark:hover:text-gray-200', children: const [ Style('size-4', child: CurrentColorIcon(_settingsSvg)), Text('Settings'), ], ), Style( 'flex items-center gap-2 border-b-2 border-transparent px-4 py-2 text-sm font-medium text-gray-600 transition-colors hover:text-gray-700 dark:text-gray-300 dark:hover:text-gray-200', children: const [ Style('size-4', child: CurrentColorIcon(_alertsSvg)), Text('Alerts'), ], ), ], ), ), const Style( 'mt-4', child: Style( 'text-gray-700 dark:text-gray-200', child: Text( 'Lorem, ipsum dolor sit amet consectetur adipisicing elit. Deserunt similique, quae hic dicta ' 'quo facere facilis praesentium a sunt, est quia pariatur nam, modi aut minus iste odio ' 'consectetur molestias iusto cupiditate ullam laborum veniam quos officia. Quos, temporibus ' 'perspiciatis!', ), ), ), ], ); }}Original HTML not vendored yet for this variant — run npm run vendor-original-html -- <category>/<slug>.
Vertical
Section titled “Vertical”Includes a dark: variant — toggle the site theme (top right) to preview it.
class Tabs3Example extends StatelessWidget { const Tabs3Example({super.key});
@override Widget build(BuildContext context) { return const Style( 'mx-auto max-w-3xl p-6', child: Style( 'flex gap-4', children: [ Style( 'border-r border-gray-200 dark:border-gray-700', child: Style( '-me-px flex flex-col gap-1', children: [ Style( 'border-r-2 border-blue-600 px-4 py-2 text-left text-sm font-medium text-blue-600 transition-colors hover:text-blue-700 dark:hover:text-blue-500', child: Text('General'), ), Style( 'border-r-2 border-transparent px-4 py-2 text-left text-sm font-medium text-gray-600 transition-colors hover:text-gray-700 dark:text-gray-300 dark:hover:text-gray-200', child: Text('Privacy'), ), Style( 'border-r-2 border-transparent px-4 py-2 text-left text-sm font-medium text-gray-600 transition-colors hover:text-gray-700 dark:text-gray-300 dark:hover:text-gray-200', child: Text('Security'), ), ], ), ), Style( 'flex-1', child: Style( 'text-gray-700 dark:text-gray-200', child: Text( 'Lorem, ipsum dolor sit amet consectetur adipisicing elit. Deserunt similique, quae hic ' 'dicta quo facere facilis praesentium a sunt, est quia pariatur nam, modi aut minus iste ' 'odio consectetur molestias iusto cupiditate ullam laborum veniam quos officia. Quos, ' 'temporibus perspiciatis!', ), ), ), ], ), ); }}Original HTML not vendored yet for this variant — run npm run vendor-original-html -- <category>/<slug>.
Underline
Section titled “Underline”Includes a dark: variant — toggle the site theme (top right) to preview it.
class Tabs4Example extends StatelessWidget { const Tabs4Example({super.key});
@override Widget build(BuildContext context) { return const Style( 'mx-auto max-w-3xl p-6', children: [ Style( 'flex gap-2', children: [ Style( 'border-b-2 border-blue-600 px-4 py-2 text-sm font-medium text-blue-600 transition-colors hover:text-blue-700 dark:hover:text-blue-500', child: Text('Overview'), ), Style( 'border-b-2 border-transparent px-4 py-2 text-sm font-medium text-gray-600 transition-colors hover:text-gray-700 dark:text-gray-300 dark:hover:text-gray-200', child: Text('Analytics'), ), Style( 'border-b-2 border-transparent px-4 py-2 text-sm font-medium text-gray-600 transition-colors hover:text-gray-700 dark:text-gray-300 dark:hover:text-gray-200', child: Text('Reports'), ), ], ), Style( 'mt-4', child: Style( 'text-gray-700 dark:text-gray-200', child: Text( 'Lorem, ipsum dolor sit amet consectetur adipisicing elit. Deserunt similique, quae hic dicta ' 'quo facere facilis praesentium a sunt, est quia pariatur nam, modi aut minus iste odio ' 'consectetur molestias iusto cupiditate ullam laborum veniam quos officia. Quos, temporibus ' 'perspiciatis!', ), ), ), ], ); }}Original HTML not vendored yet for this variant — run npm run vendor-original-html -- <category>/<slug>.
Includes a dark: variant — toggle the site theme (top right) to preview it.
class Tabs5Example extends StatelessWidget { const Tabs5Example({super.key});
@override Widget build(BuildContext context) { return const Style( 'mx-auto max-w-3xl p-6', children: [ Style( 'flex gap-2', children: [ Style( 'rounded-full bg-blue-600 px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-blue-700', child: Text('Featured'), ), Style( 'rounded-full bg-gray-200 px-4 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-300 dark:bg-gray-700 dark:text-gray-200 dark:hover:bg-gray-600', child: Text('Popular'), ), Style( 'rounded-full bg-gray-200 px-4 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-300 dark:bg-gray-700 dark:text-gray-200 dark:hover:bg-gray-600', child: Text('Trending'), ), ], ), Style( 'mt-4', child: Style( 'text-gray-700 dark:text-gray-200', child: Text( 'Lorem, ipsum dolor sit amet consectetur adipisicing elit. Deserunt similique, quae hic dicta ' 'quo facere facilis praesentium a sunt, est quia pariatur nam, modi aut minus iste odio ' 'consectetur molestias iusto cupiditate ullam laborum veniam quos officia. Quos, temporibus ' 'perspiciatis!', ), ), ), ], ); }}Original HTML not vendored yet for this variant — run npm run vendor-original-html -- <category>/<slug>.