Zen Mode Shell
A focus-mode shell: one click and the sidebar, top bar, and auxiliary panel fade out and slide away in timeline order while the main content eases back to center and scales up; exiting reverses the choreography and restores the whole shell.
npx shadcn@latest add https://webberui.com/r/zen-mode-shell.jsonPlayground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<ZenModeShell />
Installation
npx shadcn@latest add https://webberui.com/r/zen-mode-shell.jsonOr, once registries are configured in components.json, install it as @webberui/zen-mode-shell.
Usage
ZenModeShell is the frame; put ZenMain (the main content) inside it along with any combination of the ZenSidebar, ZenTopbar, and ZenPanel shell sections. Place ZenTrigger in the top bar to toggle focus mode in one click.
import {
ZenMain,
ZenModeShell,
ZenPanel,
ZenSidebar,
ZenTopbar,
ZenTrigger,
} from "@/components/ui/zen-mode-shell";
export function Example() {
return (
<ZenModeShell className="h-[420px]">
<ZenSidebar>{/* navigation */}</ZenSidebar>
<ZenTopbar>
<span className="ml-auto">
<ZenTrigger />
</span>
</ZenTopbar>
<ZenPanel>{/* supporting information */}</ZenPanel>
<ZenMain>{/* main content */}</ZenMain>
</ZenModeShell>
);
}The padding the main content leaves for the shell is derived automatically from which shell sections are mounted — omit ZenPanel and no space is reserved on the main content's right.
Controlled mode
Pass active to enter controlled mode and keep state in sync with onActiveChange; omit active and internal uncontrolled state is used instead (with defaultActive for the initial value).
const [zen, setZen] = React.useState(false);
<ZenModeShell active={zen} onActiveChange={setZen}>
{/* ... */}
</ZenModeShell>;Sizing and insets
sidebarWidth, topbarHeight, and panelWidth set both the size of each shell section and the corresponding inset of the main content, and the two always stay consistent. On entering focus mode the padding collapses to 0 and the main content naturally re-centers.
Props
ZenModeShell
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Put ZenMain plus ZenSidebar / ZenTopbar / ZenPanel here |
active | boolean | — | Controlled: whether focus mode is on; when omitted, internal uncontrolled state is used |
defaultActive | boolean | false | Initial focus state in uncontrolled mode |
onActiveChange | (active: boolean) => void | — | Fires when the focus state changes |
sidebarWidth | number | 200 | Sidebar width (px), which also sets the main content's left inset |
topbarHeight | number | 52 | Top bar height (px), which also sets the main content's top inset |
panelWidth | number | 220 | Auxiliary panel width (px), which also sets the main content's right inset |
exitLabel | string | "退出專注模式" | Accessible label and text for the exit button |
ZenSidebar / ZenTopbar / ZenPanel
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Section content |
className | string | — | Appended to the section container's className |
ZenMain
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Main content |
className | string | — | Appended to the main content container's className |
ZenTrigger
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | Icon plus "專注模式" | Custom trigger content |
className | string | — | Appended to the trigger's className |
How it works
- On entering focus mode, the sidebar, top bar, and auxiliary panel fade out and slide off towards their own edges one after another, in
ORDERsequence at a fixed interval (STEP), imitating a frame-by-frame GSAP timeline; exiting fills them back in reverse order. - The main content is positioned by the insets of the shell sections that exist; on entering, it eases its padding back, re-centers, and scales up slightly. On exiting, the main content returns to position first and only then do the shell sections fill back in (the
MAIN_LEADlead time). - The shell sections are absolutely positioned flush against the four edges, and their offsets use transforms (
x/ypercentages) so no reflow is triggered — the animations run entirely on GPU compositing. - The exit button only appears in the top-right corner once the shell has faded out, and tucks away quickly on exit.
Accessibility
Escexits focus mode.- Focus moves to the exit button when entering focus mode and returns to the
ZenTriggertrigger on exit. - In focus mode each shell section gets
inert, which removes it from the Tab order and hides it from assistive technology, so you cannot operate an interface that has already left. ZenTriggerreflects whether focus mode is on througharia-pressed.- With "reduce motion" enabled, the shell only fades in and out and the main content positions instantly without scaling, with no effect on layout or functionality.
Elastic Split Workspace
A multi-column drag-to-split panel workspace whose dividers have spring feedback; panels collapse to a thin strip in one click and the neighbouring panels reflow elastically.
Slide Over Panel
A non-modal narrow floating panel that can be dragged and magnetically snapped to either side, and flicked away to collapse into an edge handle — springs tracking the pointer throughout.