Appearance
Tabs
A tabbed interface component for organizing content into separate sections. Supports multiple variants, sizes, navigation controls, and interactive features like reordering and prefix/suffix elements.
Import
rust
use gpui_component::tab::{Tab, TabBar};Usage
Basic Tabs
rust
TabBar::new("tabs")
.selected_index(0)
.on_click(|selected_index, _, _| {
println!("Tab {} selected", selected_index);
})
.child(Tab::new().label("Account"))
.child(Tab::new().label("Profile"))
.child(Tab::new().label("Settings"))Tab Variants
Default Tabs
rust
TabBar::new("default-tabs")
.selected_index(0)
.child(Tab::new().label("Account"))
.child(Tab::new().label("Profile"))
.child(Tab::new().label("Documents"))Underline Tabs
rust
TabBar::new("underline-tabs")
.underline()
.selected_index(0)
.child(Tab::new().label("Account"))
.child(Tab::new().label("Profile"))
.child(Tab::new().label("Documents"))Pill Tabs
rust
TabBar::new("pill-tabs")
.pill()
.selected_index(0)
.child(Tab::new().label("Account"))
.child(Tab::new().label("Profile"))
.child(Tab::new().label("Documents"))Outline Tabs
rust
TabBar::new("outline-tabs")
.outline()
.selected_index(0)
.child(Tab::new().label("Account"))
.child(Tab::new().label("Profile"))
.child(Tab::new().label("Documents"))Segmented Tabs
rust
use gpui_component::IconName;
TabBar::new("segmented-tabs")
.segmented()
.selected_index(0)
.child(IconName::Bot)
.child(IconName::Calendar)
.child(IconName::Map)
.children(vec!["Settings", "About"])Tab Sizes
rust
// Extra Small
TabBar::new("tabs").xsmall()
.child(Tab::new().label("Small"))
// Small
TabBar::new("tabs").small()
.child(Tab::new().label("Small"))
// Medium (default)
TabBar::new("tabs")
.child(Tab::new().label("Medium"))
// Large
TabBar::new("tabs").large()
.child(Tab::new().label("Large"))Tabs with Icons
rust
use gpui_component::{Icon, IconName};
TabBar::new("icon-tabs")
.child(Tab::default().icon(IconName::User).with_variant(TabVariant::Tab))
.child(Tab::default().icon(IconName::Settings).with_variant(TabVariant::Tab))
.child(Tab::default().icon(IconName::Mail).with_variant(TabVariant::Tab))Tabs with Prefix and Suffix
rust
use gpui_component::button::Button;
use gpui_component::{h_flex, IconName};
TabBar::new("tabs-with-controls")
.prefix(
h_flex()
.gap_1()
.child(Button::new("back").ghost().xsmall().icon(IconName::ArrowLeft))
.child(Button::new("forward").ghost().xsmall().icon(IconName::ArrowRight))
)
.suffix(
h_flex()
.gap_1()
.child(Button::new("inbox").ghost().xsmall().icon(IconName::Inbox))
.child(Button::new("more").ghost().xsmall().icon(IconName::Ellipsis))
)
.child(Tab::new().label("Account"))
.child(Tab::new().label("Profile"))
.child(Tab::new().label("Settings"))Disabled Tabs
rust
TabBar::new("tabs-with-disabled")
.child(Tab::new().label("Account"))
.child(Tab::new().label("Profile").disabled(true))
.child(Tab::new().label("Settings"))Dynamic Tabs
rust
struct TabsView {
active_tab: usize,
tabs: Vec<String>,
}
impl Render for TabsView {
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
TabBar::new("dynamic-tabs")
.selected_index(self.active_tab)
.on_click(cx.listener(|view, index, _, cx| {
view.active_tab = *index;
cx.notify();
}))
.children(
self.tabs
.iter()
.map(|tab_name| Tab::new().label(tab_name.clone()))
)
}
}Tabs with Menu
Use menu option to enable a dropdown menu for tab selection when there are many tabs, this is default false.
If enable, the will have a dropdown button at the end of the tab bar to show all tabs in a menu.
rust
TabBar::new("tabs-with-menu")
.menu(true)
.selected_index(0)
.child(Tab::new().label("Account"))
.child(Tab::new().label("Profile"))
.child(Tab::new().label("Documents"))
.child(Tab::new().label("Mail"))
.child(Tab::new().label("Settings"))Scrollable Tabs
rust
use gpui::ScrollHandle;
struct ScrollableTabsView {
scroll_handle: ScrollHandle,
}
impl Render for ScrollableTabsView {
fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
TabBar::new("scrollable-tabs")
.track_scroll(&self.scroll_handle)
.child(Tab::new().label("Very Long Tab Name 1"))
.child(Tab::new().label("Very Long Tab Name 2"))
.child(Tab::new().label("Very Long Tab Name 3"))
.child(Tab::new().label("Very Long Tab Name 4"))
.child(Tab::new().label("Very Long Tab Name 5"))
}
}Individual Tab Configuration
rust
TabBar::new("custom-tabs")
.child(
Tab::new().label("Custom Tab")
.id("custom-id")
.prefix(IconName::Star)
.suffix(IconName::X)
.on_click(|_, _, _| {
println!("Custom tab clicked");
})
)API Reference
TabBar
| Method | Description |
|---|---|
new(id) | Create a new tab bar with the given ID |
child(tab) | Add a tab to the bar |
children(tabs) | Add multiple tabs to the bar |
selected_index(index) | Set the active tab index |
on_click(fn) | Callback when a tab is clicked, receives tab index |
prefix(element) | Add element before the tabs |
suffix(element) | Add element after the tabs |
last_empty_space(element) | Custom element for empty space at the end |
track_scroll(handle) | Enable scrolling with a scroll handle |
with_menu(bool) | Enable dropdown menu for tab selection |
TabBar Variants
| Method | Description |
|---|---|
with_variant(variant) | Set the tab variant for all children |
underline() | Use underline variant |
pill() | Use pill variant |
outline() | Use outline variant |
segmented() | Use segmented variant |
Tab
| Method | Description |
|---|---|
new(label) | Create a new tab with a label |
empty() | Create an empty tab |
icon(icon) | Create a tab with only an icon |
id(id) | Set custom ID for the tab |
with_variant(variant) | Set the tab variant |
pill() | Use pill variant |
outline() | Use outline variant |
segmented() | Use segmented variant |
underline() | Use underline variant |
prefix(element) | Add element before tab content |
suffix(element) | Add element after tab content |
disabled(bool) | Set disabled state |
selected(bool) | Set selected state (usually handled by TabBar) |
on_click(fn) | Custom click handler for individual tab |
TabVariant
rust
pub enum TabVariant {
Tab, // Default bordered tabs
Outline, // Rounded outline tabs
Pill, // Rounded pill-shaped tabs
Segmented, // Segmented control style
Underline, // Underline indicator tabs
}Styling
Both TabBar and Tab implement Sizable trait:
xsmall()- Extra small sizesmall()- Small sizemedium()- Medium size (default)large()- Large size
Advanced Examples
Custom Tab Content
rust
Tab::empty()
.child(
h_flex()
.items_center()
.gap_2()
.child(IconName::Folder)
.child("Documents")
.child(
div()
.px_1()
.py_0p5()
.text_xs()
.bg(cx.theme().accent)
.text_color(cx.theme().accent_foreground)
.rounded_sm()
.child("12")
)
)Tabs with State Management
rust
struct TabsWithContent {
active_tab: usize,
tab_contents: Vec<String>,
}
impl TabsWithContent {
fn render_tab_content(&self, cx: &mut Context<Self>) -> impl IntoElement {
match self.active_tab {
0 => div().child("Account content"),
1 => div().child("Profile content"),
2 => div().child("Settings content"),
_ => div().child("Unknown content"),
}
}
}
impl Render for TabsWithContent {
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
v_flex()
.child(
TabBar::new("content-tabs")
.selected_index(self.active_tab)
.on_click(cx.listener(|view, index, _, cx| {
view.active_tab = *index;
cx.notify();
}))
.child(Tab::new().label("Account"))
.child(Tab::new().label("Profile"))
.child(Tab::new().label("Settings"))
)
.child(
div()
.flex_1()
.p_4()
.child(self.render_tab_content(cx))
)
}
}Tabs with Close Buttons
While the basic Tab component doesn't include closeable functionality, you can create closeable tabs using suffix elements:
rust
struct CloseableTabsView {
tabs: Vec<String>,
active_tab: usize,
}
impl CloseableTabsView {
fn close_tab(&mut self, index: usize, cx: &mut Context<Self>) {
if self.tabs.len() > 1 {
self.tabs.remove(index);
if self.active_tab >= index && self.active_tab > 0 {
self.active_tab -= 1;
}
cx.notify();
}
}
}
impl Render for CloseableTabsView {
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
TabBar::new("closeable-tabs")
.selected_index(self.active_tab)
.on_click(cx.listener(|view, index, _, cx| {
view.active_tab = *index;
cx.notify();
}))
.children(
self.tabs
.iter()
.enumerate()
.map(|(index, tab_name)| {
Tab::new().label(tab_name.clone())
.suffix(
Button::new(format!("close-{}", index))
.icon(IconName::X)
.ghost()
.xsmall()
.on_click(cx.listener(move |view, _, _, cx| {
view.close_tab(index, cx);
}))
)
})
)
}
}Notes
- The
TabBarmanages the selection state of all child tabs - Individual tab
on_clickhandlers are ignored whenTabBar.on_clickis set - Tabs automatically inherit the variant and size from their parent
TabBar - The
with_menuoption adds a dropdown for tab selection when there are many tabs - Scrolling is automatically enabled when tabs overflow the container width
- The dock system provides advanced closeable tab functionality for complex layouts