Component 11 of 60
Collapsible
An interactive panel that expands and collapses.
Starting the preview. GPUI compiles to WebAssembly, so the first load takes a few seconds. This browser has neither WebGPU nor WebGL 2, so the live preview cannot run. The code on this page still works. The preview did not start.
fn collapsible_preview(&self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let theme = UiTheme::read(cx).clone();
let project = |name: &'static str| {
div()
.w_full()
.rounded(theme.radius.lg)
.border_1()
.border_color(theme.colors.border)
.px(theme.space(4.))
.py(theme.space(2.5))
.font_family(theme.fonts.mono.clone())
.text_size(theme.text(13.))
.child(name)
};
div().w(px(340.)).h(px(240.)).child(
collapsible("preview.projects", self.collapsible_open, window, cx)
.gap(theme.space(2.))
.child(
div()
.flex()
.items_center()
.justify_between()
.child(
div()
.font_weight(gpui_kit::FontWeight::MEDIUM)
.child("Recent projects"),
)
.child(
collapsible_trigger("preview.disclosure", self.collapsible_open, cx)
.accessibility_label("Toggle recent projects")
.child(
lucide(LucideIcon::ChevronsUpDown)
.size(theme.space(4.))
.text_color(theme.colors.foreground),
)
.on_click(cx.listener(|this, _, _, cx| {
this.collapsible_open = !this.collapsible_open;
cx.notify();
})),
),
)
.child(project("Design system"))
.content(
collapsible_content(cx)
.pt(px(0.))
.flex()
.flex_col()
.gap(theme.space(2.))
.child(project("Documentation"))
.child(project("Website")),
),
)
}
Installation
After the one-time setup, run the command from your app root. The CLI
writes the modules and keeps src/ui/mod.rs in step.
gpuicn add collapsible
If you prefer to copy the files by hand, declare them yourself:
// src/ui/mod.rs
pub mod theme;
pub mod collapsible;
// src/main.rs
mod ui;
Usage
Put this in a view module and return example(open, window, cx) from its render method.
use crate::ui::collapsible::*;
use gpui_kit::{App, IntoElement, ParentElement, Window};
fn example(open: bool, window: &mut Window, cx: &mut App) -> impl IntoElement {
collapsible("projects-region", open, window, cx)
.child(collapsible_trigger("projects", open, cx).child("Recent projects"))
.content(collapsible_content(cx).child("Design system"))
}
API reference
pub fn collapsible(
id: impl Into<ElementId>,
open: bool,
window: &mut Window,
cx: &mut App,
) -> Collapsible
Creates a controlled region that reveals and removes its content with theme motion.
pub fn collapsible_trigger(id: impl Into<ElementId>, open: bool, cx: &App) -> Button
Creates an accessible trigger. Update the caller's open state in its click handler.
pub fn collapsible_content(cx: &App) -> Div
Creates the disclosure content's text treatment.
Installed source, 57 lines
//! Nova presentation for GPUI Kit's controlled collapsible region.
use super::theme::UiTheme;
use gpui_kit::base::Button;
pub use gpui_kit::base::Collapsible;
use gpui_kit::{
App, Div, ElementId, InteractiveElement as _, StatefulInteractiveElement as _, Styled, Window,
div,
};
/// Creates a controlled region that reveals and removes its content with theme motion.
pub fn collapsible(
id: impl Into<ElementId>,
open: bool,
window: &mut Window,
cx: &mut App,
) -> Collapsible {
let id = id.into();
let presence = super::theme::presence(id.clone(), open, window, cx);
let visible = presence.should_render() && (open || presence.progress > 0.);
let mut region = Collapsible::new().open(visible);
if visible {
region = region.reveal(id, presence.progress);
}
region
.flex()
.flex_col()
.font_family(UiTheme::read(cx).fonts.body.clone())
}
/// Creates an accessible trigger. Update the caller's open state in its click handler.
pub fn collapsible_trigger(id: impl Into<ElementId>, open: bool, cx: &App) -> Button {
let theme = UiTheme::read(cx);
let colors = theme.colors;
Button::new(id)
.aria_expanded(open)
.px(theme.space(2.5))
.py(theme.space(1.5))
.rounded(theme.radius.lg)
.border_1()
.border_color(colors.background.opacity(0.))
.text_size(theme.text(14.))
.text_color(colors.foreground)
.cursor_pointer()
.hover(move |s| s.bg(colors.muted))
.focus_visible(move |s| s.border_color(colors.ring))
}
/// Creates the disclosure content's text treatment.
pub fn collapsible_content(cx: &App) -> Div {
let theme = UiTheme::read(cx);
div()
.w_full()
.pt(theme.space(2.))
.overflow_hidden()
.font_family(theme.fonts.body.clone())
.text_size(theme.text(14.))
.text_color(theme.colors.foreground)
}
Platform notes
Visual reference: shadcn/ui 4.19.0, Neutral Nova. Implementation:
crates/ui/registry/collapsible/collapsible.rs, using GPUI Kit 0.6.4.
The application passes open state and handles the trigger click. Kit supplies the disclosure host and trigger; gpuicn adds Nova spacing and typography.
The Rust source and Usage example define the supported API. Browser DOM/CSS behavior, exact exit animations and cross-platform screen-reader parity are not implied by the native component. See migration qualification for the checks completed on this revision.