WebberUI

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.

Loading preview…
npx shadcn@latest add https://webberui.com/r/zen-mode-shell.json

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

200
52
220
<ZenModeShell />

Installation

npx shadcn@latest add https://webberui.com/r/zen-mode-shell.json

Or, 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

PropTypeDefaultDescription
childrenReactNodePut ZenMain plus ZenSidebar / ZenTopbar / ZenPanel here
activebooleanControlled: whether focus mode is on; when omitted, internal uncontrolled state is used
defaultActivebooleanfalseInitial focus state in uncontrolled mode
onActiveChange(active: boolean) => voidFires when the focus state changes
sidebarWidthnumber200Sidebar width (px), which also sets the main content's left inset
topbarHeightnumber52Top bar height (px), which also sets the main content's top inset
panelWidthnumber220Auxiliary panel width (px), which also sets the main content's right inset
exitLabelstring"退出專注模式"Accessible label and text for the exit button

ZenSidebar / ZenTopbar / ZenPanel

PropTypeDefaultDescription
childrenReactNodeSection content
classNamestringAppended to the section container's className

ZenMain

PropTypeDefaultDescription
childrenReactNodeMain content
classNamestringAppended to the main content container's className

ZenTrigger

PropTypeDefaultDescription
childrenReactNodeIcon plus "專注模式"Custom trigger content
classNamestringAppended 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 ORDER sequence 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_LEAD lead time).
  • The shell sections are absolutely positioned flush against the four edges, and their offsets use transforms (x / y percentages) 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

  • Esc exits focus mode.
  • Focus moves to the exit button when entering focus mode and returns to the ZenTrigger trigger 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.
  • ZenTrigger reflects whether focus mode is on through aria-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.

On this page