The Tabs component provides a tabbed navigation interface for switching between different content panels.
Basic Usage
import reflex_ui as ui
ui.tabs.root(
ui.tabs.list(
ui.tabs.tab("Tab 1", value="1"),
ui.tabs.tab("Tab 2", value="2"),
ui.tabs.tab("Tab 3", value="3"),
ui.tabs.indicator()
),
ui.tabs.panel("Content for tab 1", value="1"),
ui.tabs.panel("Content for tab 2", value="2"),
ui.tabs.panel("Content for tab 3", value="3"),
default_value="1"
)
Controlled State
class State(rx.State):
active_tab: str = "home"
ui.tabs.root(
ui.tabs.list(
ui.tabs.tab("Home", value="home"),
ui.tabs.tab("Profile", value="profile"),
ui.tabs.tab("Settings", value="settings"),
ui.tabs.indicator()
),
ui.tabs.panel("Home content", value="home"),
ui.tabs.panel("Profile content", value="profile"),
ui.tabs.panel("Settings content", value="settings"),
value=State.active_tab,
on_value_change=State.set_active_tab
)
Props Reference
tabs.root
Currently selected tab (controlled)
Initially selected tab (uncontrolled)
Event fired when tab selection changes
orientation
Literal['horizontal', 'vertical']
default:"horizontal"
Layout direction of tabs
tabs.list
Whether arrow keys automatically activate tabs (vs requiring Enter/Space)
Whether arrow keys loop to first tab at the end
tabs.tab
Unique identifier for this tab
tabs.panel
Matches the corresponding tab’s value
Keep panel in DOM when not active (for animations)
With Icons
ui.tabs.root(
ui.tabs.list(
ui.tabs.tab(
ui.icon("HomeIcon"),
"Home",
value="home"
),
ui.tabs.tab(
ui.icon("UserIcon"),
"Profile",
value="profile"
),
ui.tabs.indicator()
),
ui.tabs.panel("Home content", value="home"),
ui.tabs.panel("Profile content", value="profile"),
default_value="home"
)
Vertical Orientation
ui.tabs.root(
ui.tabs.list(
ui.tabs.tab("Section 1", value="1"),
ui.tabs.tab("Section 2", value="2"),
ui.tabs.indicator()
),
ui.tabs.panel("Content 1", value="1"),
ui.tabs.panel("Content 2", value="2"),
orientation="vertical",
class_name="flex-row gap-4"
)
Disabled Tabs
ui.tabs.list(
ui.tabs.tab("Active", value="1"),
ui.tabs.tab("Disabled", value="2", disabled=True),
ui.tabs.tab("Active", value="3"),
ui.tabs.indicator()
)
Dynamic Tabs
class State(rx.State):
tabs: list[dict] = [
{"value": "tab1", "label": "Tab 1", "content": "Content 1"},
{"value": "tab2", "label": "Tab 2", "content": "Content 2"}
]
ui.tabs.root(
ui.tabs.list(
rx.foreach(
State.tabs,
lambda tab: ui.tabs.tab(tab["label"], value=tab["value"])
),
ui.tabs.indicator()
),
rx.foreach(
State.tabs,
lambda tab: ui.tabs.panel(tab["content"], value=tab["value"])
)
)
Tabs Components
tabs.root
Container for the entire tabs component.
ui.tabs.root(
ui.tabs.list(...),
ui.tabs.panel(...),
default_value="1"
)
tabs.list
Container for tab buttons.
ui.tabs.list(
ui.tabs.tab("Tab 1"),
ui.tabs.tab("Tab 2"),
ui.tabs.indicator(),
activate_on_focus=True
)
tabs.tab
Individual tab button.
ui.tabs.tab(
"Label",
value="unique-id",
disabled=False
)
tabs.indicator
Animated visual indicator showing active tab.
ui.tabs.indicator() # Animates position and width
Render indicator before React hydrates (reduces flash)
tabs.panel
Content area for a tab.
ui.tabs.panel(
rx.text("Panel content"),
value="matching-tab-id",
keep_mounted=True
)
Styling Classes
Access predefined styles via ui.tabs.class_names:
ROOT: Flex column layout
LIST: Rounded background with padding, inline flex
TAB: Tab button with hover and selected states
INDICATOR: Animated underline/background indicator
PANEL: Content panel layout
Indicator Animation
The indicator automatically:
- Moves to the active tab’s position
- Resizes to match the active tab’s width
- Uses smooth CSS transitions (200ms ease-in-out)
- Positioned using CSS custom properties
Keyboard Navigation
- Arrow Left/Up: Move to previous tab
- Arrow Right/Down: Move to next tab
- Home: Jump to first tab
- End: Jump to last tab
- Enter/Space: Activate focused tab (when activate_on_focus=False)
Accessibility
- Proper ARIA roles and attributes
- Keyboard navigation support
- Focus management
- Screen reader announcements
- Selected state indication
Common Patterns
With State Management
class AppState(rx.State):
tab: str = "overview"
def handle_tab_change(self, value: str):
self.tab = value
# Perform side effects like fetching data
if value == "analytics":
self.load_analytics()
Conditional Content
ui.tabs.panel(
rx.cond(
State.data_loaded,
display_data(),
ui.spinner()
),
value="data-tab"
)
Implementation Details
From source code at reflex_ui/components/base/tabs.py:36:
- Built on Base UI Tabs primitives
- Indicator uses CSS custom properties for position/size
- Tab button has hover and selected states
- List has background and rounded corners
- Panel content can be kept mounted for animations