# Layout

A compound component system for building application shells with headers, footers, sidebars, and scrollable content areas. The Layout system handles overflow management, panel resizing, and smooth transitions automatically.

## When to Use

- Building application shells with sidebars and navigation panels
- Creating pages with headers, footers, and scrollable content
- Implementing resizable side panels for tools or details views
- Managing complex layouts with nested content areas

## Component

---

### Properties

- **`doNotOverflow`** `boolean` (default: `false`) — When true, applies `overflow: hidden` to the root element. By default, overflow is visible.
- **`contentPadding`** `string` (default: `'1x'`) — Padding for content areas (`Layout.Content` components). Sets the `$content-padding` token inherited by sub-components.
- **`hasTransition`** `boolean` (default: `false`) — Enable transition animation for the Inner content when panels open/close
- **`minContentSize`** `number` (default: `320`) — Minimum size in pixels reserved for the content area between panels
- **`innerRef`** `ForwardedRef<HTMLDivElement>` — Ref for the inner content element
- **`innerProps`** `HTMLAttributes<HTMLDivElement>` — Props to spread on the Inner sub-element
- **`isGrid`** `boolean` — Enable grid display mode
- **`columns`** `string` — Grid template columns (when `isGrid` is enabled)
- **`rows`** `string` — Grid template rows (when `isGrid` is enabled)
- **`template`** `string` — Grid template shorthand (when `isGrid` is enabled)

### Base Properties

Supports [Base properties](../../BaseProperties.md).

### Styling Properties

#### styles

Customizes the root Layout element.

**Sub-elements:**
- `Inner` - The inner content wrapper that adjusts based on panel sizes

### Style Properties

These properties allow direct style application without using the `styles` prop:

- **Position:** `gridArea`, `order`, `gridColumn`, `gridRow`, `placeSelf`, `alignSelf`, `justifySelf`, `zIndex`, `margin`, `inset`, `position`
- **Dimension:** `width`, `height`, `flexBasis`, `flexGrow`, `flexShrink`, `flex`
- **Block:** `border`, `radius`, `shadow`, `outline`

### Style Defaults

- `position` — `relative`
- `display` — `block`
- `overflow` — `visible` (switches to `hidden` when `doNotOverflow`)
- `flexGrow` — `1`
- `placeSelf` — `stretch`
- `$content-padding` — `1x` (inherited by all sub-components for consistent inner padding)

**Inner element:**
- `position` — `absolute`
- `inset` — Adjusts based on registered panel sizes
- `display` — `flex`
- `flow` — `column`
- `transition` — `inset` (only when `hasTransition` is enabled on panels)

---

## Sub-Components

### Layout.Toolbar

A horizontal bar typically placed at the top for navigation and actions.

```jsx
<Layout.Toolbar>
  <Title level={4}>App Name</Title>
  <Space>
    <Button>Settings</Button>
    <Button type="primary">Profile</Button>
  </Space>
</Layout.Toolbar>
```

- **`children`** `ReactNode` — Content split between left and right

**Sub-elements:**
- No sub-elements, styles apply to container

---

### Layout.Header

A semantic page header with title, breadcrumbs, subtitle, and action areas.

```jsx
<Layout.Header
  title="Dashboard"
  level={2}
  breadcrumbs={[
    ['Home', '/'],
    ['Reports', '/reports'],
  ]}
  subtitle="Overview of your metrics"
  extra={<Button type="primary">Create</Button>}
/>
```

- **`title`** `ReactNode` — Page/section title
- **`level`** `1-6` (default: `3`) — Heading level for accessibility
- **`breadcrumbs`** `[label, href][]` — Navigation breadcrumbs
- **`subtitle`** `ReactNode` — Text below the title
- **`suffix`** `ReactNode` — Content next to the title
- **`extra`** `ReactNode` — Content on the right side
- **`onBack`** `() => void` — Callback for the back button. When provided, a back arrow button appears to the left of the title.

**Sub-elements:**
- `Back` - Back button container (visible when `onBack` is provided)
- `Breadcrumbs` - Navigation path container
- `Title` - Main heading element
- `Suffix` - Content adjacent to title
- `Extra` - Right-aligned actions
- `Subtitle` - Secondary text below title

---

### Layout.Content

Scrollable content area with automatic overflow handling and custom scrollbar styles.

```jsx
<Layout.Content scrollbar="tiny">
  {/* Scrollable content */}
</Layout.Content>
```

- **`scrollbar`** `'default' | 'thin' | 'tiny' | 'none'` (default: `'thin'`) — Scrollbar style
- **`children`** `ReactNode` — Content to display
- **`innerRef`** `ForwardedRef<HTMLDivElement>` — Ref for the inner content element
- **`innerProps`** `HTMLAttributes<HTMLDivElement>` — Props to spread on the Inner sub-element

**Scrollbar types:**
- `default` - Browser default scrollbar
- `thin` - Thin scrollbar (CSS native)
- `tiny` - Custom hover-visible indicator (3px)
- `none` - Hidden scrollbar (still scrollable)

**Sub-elements:**
- `Inner` - Scrollable inner container
- `ScrollbarV` - Vertical scroll indicator (tiny mode)
- `ScrollbarH` - Horizontal scroll indicator (tiny mode)

---

### Layout.Container

Horizontally centered content area with constrained width. Ideal for forms, articles, and focused content that shouldn't span the full width.

```jsx
<Layout.Container>
  <Title>Article Title</Title>
  <Text>Content is centered horizontally with a max-width constraint.</Text>
</Layout.Container>
```

- **`children`** `ReactNode` — Content to display
- **`innerRef`** `ForwardedRef<HTMLDivElement>` — Ref for the inner content element
- **`innerProps`** `HTMLAttributes<HTMLDivElement>` — Props to spread on the Inner sub-element

**Width constraints:**
- Minimum: `40x` (320px at default gap)
- Default: `100%`
- Maximum: `120x` (960px at default gap)

**Sub-elements:**
- `Inner` - Constrained width inner container

---

### Layout.Center

Centered content area for both horizontal and vertical alignment. Extends `Layout.Container` with vertical centering and text alignment. Ideal for empty states, loading screens, and hero sections.

```jsx
<Layout.Center>
  <Title>No Results</Title>
  <Text>Try adjusting your search criteria.</Text>
  <Button type="primary">Clear Filters</Button>
</Layout.Center>
```

- **`children`** `ReactNode` — Content to display
- **`isGoldenRatio`** `boolean` (default: `false`) — Position content slightly above the geometric center using the golden ratio (~38.2% empty space above, ~61.8% below). Only applies while content fits inside the container; once content overflows, falls back to the default centered behavior.

**Styling differences from Container:**
- Content is centered both horizontally and vertically
- Text is center-aligned by default

**Sub-elements:**
- `Inner` - Constrained width inner container with `text-align: center`

---

### Layout.Footer

Footer area with support for inverted content order (primary actions on right).

```jsx
<Layout.Footer invertOrder>
  <Button.Group>
    <Button type="primary">Save</Button>
    <Button>Cancel</Button>
  </Button.Group>
  <Text color="#dark-03">Draft saved</Text>
</Layout.Footer>
```

- **`invertOrder`** `boolean` (default: `false`) — Reverse child order (primary on right)
- **`children`** `ReactNode` — Footer content

---

### Layout.Panel

Collapsible side panel with resizing, transitions, and multiple rendering modes.

```jsx
<Layout.Panel
  side="left"
  size={250}
  isResizable
  minSize={150}
  maxSize={400}
  hasTransition
  isOpen={isPanelOpen}
  onOpenChange={setIsPanelOpen}
  onSizeChange={setSize}
>
  <Layout.PanelHeader isClosable title="Navigation" onClose={() => setIsPanelOpen(false)} />
  <Layout.Content>
    {/* Panel content */}
  </Layout.Content>
</Layout.Panel>
```

- **`side`** `'left' | 'right' | 'top' | 'bottom'` (default: `'left'`) — Panel position
- **`mode`** `'default' | 'sticky' | 'overlay' | 'dialog'` (default: `'default'`) — Panel rendering mode
- **`size`** `number` — Controlled panel size (px)
- **`defaultSize`** `number` (default: `280`) — Initial uncontrolled size
- **`minSize`** `number` (default: `200`) — Minimum size constraint
- **`maxSize`** `number` — Maximum size constraint
- **`isResizable`** `boolean` (default: `false`) — Enable drag-to-resize
- **`isOpen`** `boolean` — Controlled open state
- **`defaultIsOpen`** `boolean` (default: `true`) — Initial open state
- **`onOpenChange`** `(isOpen: boolean) => void` — Open state callback
- **`onSizeChange`** `(size: number) => void` — Size change callback
- **`sizeStorageKey`** `string` — localStorage key for persisting size
- **`hasTransition`** `boolean` (default: `false`) — Enable slide animation
- **`isDismissable`** `boolean` (default: `true`) — Allow dismissing overlay/dialog by click or Escape
- **`overlayStyles`** `Styles` — Styles for the overlay backdrop in overlay mode
- **`isDialogOpen`** `boolean` — Controlled dialog state (mode="dialog")
- **`defaultIsDialogOpen`** `boolean` (default: `false`) — Initial dialog state
- **`onDialogOpenChange`** `(isOpen: boolean) => void` — Dialog state callback
- **`dialogProps`** `CubeDialogContainerProps` — Props for dialog mode
- **`innerRef`** `ForwardedRef<HTMLDivElement>` — Ref for the inner content element
- **`innerProps`** `HTMLAttributes<HTMLDivElement>` — Props to spread on the Inner sub-element

**Panel Modes:**

- `default` — Standard panel that pushes content aside (propagates size, no overlay)
- `sticky` — Panel floats over content without affecting layout (no size propagation, no overlay)
- `overlay` — Panel with dismissable backdrop overlay (propagates size, with overlay)
- `dialog` — Panel renders as a modal dialog (no size propagation, overlay via Dialog)

**Modifiers:**

- `side` `'left' | 'right' | 'top' | 'bottom'` — Panel position
- `drag` `boolean` — Currently being resized
- `horizontal` `boolean` — Left or right panel
- `has-transition` `boolean` — Transition enabled
- `offscreen` `boolean` — Panel is collapsed

---

### Layout.Pane

Resizable inline section within a layout. Unlike Layout.Panel (which is absolutely positioned), Pane participates in the normal flex/grid flow and can be resized via drag handles.

```jsx
<Layout.Pane
  isResizable
  resizeEdge="right"
  size={250}
  minSize={150}
  maxSize={400}
  onSizeChange={setSize}
>
  <Title level={5}>Pane Content</Title>
  <Text>This pane can be resized by dragging the edge.</Text>
</Layout.Pane>
```

- **`resizeEdge`** `'right' | 'bottom'` (default: `'right'`) — Edge where resize handler appears
- **`isResizable`** `boolean` (default: `false`) — Enable resize functionality
- **`size`** `number | string` — Controlled size (width for right edge, height for bottom edge)
- **`defaultSize`** `number | string` (default: `200`) — Default size for uncontrolled state
- **`minSize`** `number | string` — Minimum size constraint
- **`maxSize`** `number | string` — Maximum size constraint
- **`onSizeChange`** `(size: number) => void` — Size change callback
- **`scrollbar`** `ScrollbarType` (default: `'thin'`) — Scrollbar style
- **`children`** `ReactNode` — Content to display
- **`innerRef`** `ForwardedRef<HTMLDivElement>` — Ref for the inner content element
- **`innerProps`** `HTMLAttributes<HTMLDivElement>` — Props to spread on the Inner sub-element

**Sub-elements:**
- `Inner` - Scrollable inner container
- `ScrollbarV` - Vertical scroll indicator (tiny mode)
- `ScrollbarH` - Horizontal scroll indicator (tiny mode)
- `ResizeHandler` - Drag handle for resizing
- `Drag` - Visual drag indicator
- `DragPart` - Individual dots in the drag indicator

---

### Layout.PanelHeader

Header for panels with optional close button.

```jsx
<Layout.PanelHeader
  title="Details"
  isClosable
  onClose={() => setOpen(false)}
/>
```

- **`title`** `ReactNode` — Panel title
- **`level`** `1-6` (default: `2`) — Heading level
- **`isClosable`** `boolean` (default: `false`) — Show close button
- **`onClose`** `() => void` — Close button handler
- **`actions`** `ReactNode` — Custom actions (replaces close)

---

## GridLayout

A variant of Layout that enables CSS Grid for the content area.

```jsx
<GridLayout
  height="100dvh"
  columns="repeat(2, 1fr)"
  rows="auto 1fr"
  gap="2x"
  padding="2x"
>
  <Layout.Header title="Grid Dashboard" />
  <div style={{ gridColumn: '1 / -1' }}>Full-width card</div>
  <div>Left card</div>
  <div>Right card</div>
</GridLayout>
```

- **`columns`** `string` — Grid template columns
- **`rows`** `string` — Grid template rows
- **`template`** `string` — Grid template shorthand
- **`gap`** `string` — Grid gap

---

## Examples

### Basic Layout with Header and Content

```jsx
<Layout height="100dvh">
  <Layout.Header title="Dashboard" subtitle="Overview of your data" />
  <Layout.Content>
    <Text>Main content area</Text>
  </Layout.Content>
  <Layout.Footer>
    <Text preset="t4" color="#dark-03">© 2024 Company</Text>
  </Layout.Footer>
</Layout>
```

### With Breadcrumb Navigation

```jsx
<Layout height="100dvh">
  <Layout.Header
    title="Analytics"
    breadcrumbs={[
      ['Home', '/'],
      ['Reports', '/reports'],
    ]}
    extra={
      <Button.Group>
        <Button>Export</Button>
        <Button type="primary">New Report</Button>
      </Button.Group>
    }
  />
  <Layout.Content>
    <Text>Analytics content</Text>
  </Layout.Content>
</Layout>
```

### With Back Button

```jsx
<Layout height="100dvh">
  <Layout.Header
    title="Report Details"
    onBack={() => navigate(-1)}
    extra={
      <Space>
        <Button>Export</Button>
        <Button type="primary">Edit</Button>
      </Space>
    }
  />
  <Layout.Content>
    <Text>Page content with a back button in the header</Text>
  </Layout.Content>
</Layout>
```

### Resizable Side Panel

```jsx
function ResizablePanelExample() {
  const [size, setSize] = useState(250);

  return (
    <Layout height="100dvh">
      <Layout.Panel
        isResizable
        side="left"
        size={size}
        minSize={150}
        maxSize={400}
        onSizeChange={setSize}
      >
        <Layout.PanelHeader title="Resizable" />
        <Layout.Content>
          <Text>Drag the edge to resize (current: {size}px)</Text>
        </Layout.Content>
      </Layout.Panel>
      <Layout.Content>
        <Text>Main content area</Text>
      </Layout.Content>
    </Layout>
  );
}
```

### Persistent Panel Size

Use `sizeStorageKey` to persist panel size to localStorage. The size is automatically restored on mount.

```jsx
<Layout height="100dvh">
  <Layout.Panel
    isResizable
    side="left"
    sizeStorageKey="app-sidebar-size"
    defaultSize={250}
    minSize={150}
    maxSize={400}
  >
    <Layout.PanelHeader title="Persistent" />
    <Layout.Content>
      <Text>This panel remembers its size</Text>
    </Layout.Content>
  </Layout.Panel>
  <Layout.Content>
    <Text>Main content area</Text>
  </Layout.Content>
</Layout>
```

### Panel with Slide Transition

```jsx
function PanelWithTransitionExample() {
  const [isPanelOpen, setIsPanelOpen] = useState(true);

  return (
    <Layout height="100dvh">
      <Layout.Panel
        hasTransition
        side="right"
        size={250}
        isOpen={isPanelOpen}
        onOpenChange={setIsPanelOpen}
      >
        <Layout.PanelHeader
          isClosable
          title="Details"
          onClose={() => setIsPanelOpen(false)}
        />
        <Layout.Content>
          <Text>Panel content with slide transition</Text>
        </Layout.Content>
      </Layout.Panel>
      <Layout.Toolbar>
        <Button onPress={() => setIsPanelOpen(!isPanelOpen)}>
          {isPanelOpen ? 'Close' : 'Open'} Panel
        </Button>
      </Layout.Toolbar>
      <Layout.Content>
        <Text>Main content area</Text>
      </Layout.Content>
    </Layout>
  );
}
```

### Multiple Panels

```jsx
function MultiplePanelsExample() {
  const [leftOpen, setLeftOpen] = useState(true);
  const [rightOpen, setRightOpen] = useState(true);

  return (
    <Layout height="100dvh">
      <Layout.Panel hasTransition side="left" size={180} isOpen={leftOpen}>
        <Layout.PanelHeader isClosable title="Left" onClose={() => setLeftOpen(false)} />
        <Layout.Content>
          <Text>Left panel</Text>
        </Layout.Content>
      </Layout.Panel>
      <Layout.Panel hasTransition side="right" size={180} isOpen={rightOpen}>
        <Layout.PanelHeader isClosable title="Right" onClose={() => setRightOpen(false)} />
        <Layout.Content>
          <Text>Right panel</Text>
        </Layout.Content>
      </Layout.Panel>
      <Layout.Toolbar>
        <Space>
          <Button onPress={() => setLeftOpen(!leftOpen)}>Left</Button>
          <Button onPress={() => setRightOpen(!rightOpen)}>Right</Button>
        </Space>
      </Layout.Toolbar>
      <Layout.Content>
        <Text>Main content between two panels</Text>
      </Layout.Content>
    </Layout>
  );
}
```

### Sticky Panel

In `sticky` mode, the panel floats over the content without pushing it aside. The main content area remains unaffected by the panel's size.

```jsx
function StickyPanelExample() {
  const [isPanelOpen, setIsPanelOpen] = useState(true);

  return (
    <Layout height="100dvh">
      <Layout.Panel
        hasTransition
        mode="sticky"
        side="left"
        size={260}
        isOpen={isPanelOpen}
        onOpenChange={setIsPanelOpen}
      >
        <Layout.PanelHeader isClosable title="Sticky Panel" onClose={() => setIsPanelOpen(false)} />
        <Layout.Content>
          <Text>This panel floats over the content.</Text>
        </Layout.Content>
      </Layout.Panel>
      <Layout.Content>
        <Text>Main content stays in place.</Text>
      </Layout.Content>
    </Layout>
  );
}
```

### Overlay Panel

In `overlay` mode, a semi-transparent backdrop appears behind the panel. The panel is dismissed (when `isDismissable` is true, which is the default) when:
- Clicking the backdrop overlay
- Pressing Escape anywhere in the Layout
- Moving focus to the main content area

```jsx
function OverlayPanelExample() {
  const [isPanelOpen, setIsPanelOpen] = useState(true);

  return (
    <Layout height="100dvh">
      <Layout.Panel
        hasTransition
        mode="overlay"
        side="right"
        size={300}
        isOpen={isPanelOpen}
        onOpenChange={setIsPanelOpen}
      >
        <Layout.PanelHeader isClosable title="Overlay Panel" onClose={() => setIsPanelOpen(false)} />
        <Layout.Content>
          <Text>Click the overlay, press Escape, or focus the main content to close.</Text>
        </Layout.Content>
      </Layout.Panel>
      <Layout.Content>
        <Text>Background content is dimmed.</Text>
      </Layout.Content>
    </Layout>
  );
}
```

You can customize the overlay styles using the `overlayStyles` prop:

```jsx
<Layout.Panel mode="overlay" overlayStyles={{ fill: '#dark.5' }}>
  {/* Panel with darker overlay */}
</Layout.Panel>
```

To prevent dismissing the overlay by clicking or pressing Escape, set `isDismissable={false}`:

```jsx
<Layout.Panel mode="overlay" isDismissable={false}>
  {/* User must use explicit controls to close */}
</Layout.Panel>
```

### Tiny Scrollbar

```jsx
<Layout height="100dvh">
  <Layout.Header title="Tiny Scrollbar" />
  <Layout.Content scrollbar="tiny">
    {Array.from({ length: 20 }, (_, i) => (
      <div key={i} style={{ padding: '8px' }}>
        <Text>Line {i + 1}: Hover to reveal scrollbar indicator.</Text>
      </div>
    ))}
  </Layout.Content>
</Layout>
```

### Nested Layouts

```jsx
<Layout height="100dvh">
  <Layout.Header title="Nested Layouts" />
  <Layout flow="row">
    <Layout width="200px" border="right">
      <Layout.Content>
        <Text>Left sidebar</Text>
      </Layout.Content>
    </Layout>
    <Layout>
      <Layout.Toolbar>
        <Text>Inner toolbar</Text>
      </Layout.Toolbar>
      <Layout.Content>
        <Text>Main content</Text>
      </Layout.Content>
    </Layout>
  </Layout>
</Layout>
```

### Complete Application Shell

```jsx
function ApplicationShell() {
  const [sidebarOpen, setSidebarOpen] = useState(true);

  return (
    <Layout height="100dvh">
      <Layout.Panel
        hasTransition
        isResizable
        side="right"
        defaultSize={240}
        isOpen={sidebarOpen}
        minSize={180}
        maxSize={350}
        onOpenChange={setSidebarOpen}
      >
        <Layout.PanelHeader
          isClosable
          title="Navigation"
          onClose={() => setSidebarOpen(false)}
        />
        <Layout.Content padding=".5x" scrollbar="tiny" gap="1bw">
          {['Dashboard', 'Analytics', 'Reports'].map((item) => (
            <ItemButton key={item} type="clear" width="100%">
              {item}
            </ItemButton>
          ))}
        </Layout.Content>
      </Layout.Panel>

      <Layout.Header
        title="Dashboard"
        level={2}
        breadcrumbs={[['Home', '/'], ['Analytics', '/analytics']]}
        subtitle="Real-time overview of your metrics"
        suffix={
          <Button type="clear" onPress={() => setSidebarOpen(!sidebarOpen)}>
            ☰
          </Button>
        }
        extra={
          <Button.Group>
            <Button>Export</Button>
            <Button type="primary">Create Report</Button>
          </Button.Group>
        }
      />

      <Layout.Content scrollbar="tiny">
        {/* Main content */}
      </Layout.Content>

      <Layout.Footer>
        <Text preset="t4" color="#dark-03">© 2024 Your Company</Text>
        <Space>
          <Button type="link" size="small">Privacy</Button>
          <Button type="link" size="small">Terms</Button>
        </Space>
      </Layout.Footer>
    </Layout>
  );
}
```

---

## Accessibility

### Keyboard Navigation

- `Tab` - Navigate between interactive elements
- Focus management is handled automatically when panels open/close
- Resize handlers can be focused and resized using arrow keys:
  - `Arrow keys` - Resize panel by 10px
  - `Shift + Arrow keys` - Resize panel by 50px
  - `Double-click` on resize handler - Reset to default size

### Screen Reader Support

- `Layout.Header` uses semantic heading elements (`h1`-`h6`) based on `level` prop
- `Layout.Toolbar` has `role="toolbar"` for proper announcement
- `Layout.Footer` has `role="contentinfo"` for landmark navigation
- Breadcrumbs use Link components with proper navigation semantics
- Panel close buttons have accessible labels

### ARIA Properties

- `aria-label` - Available on all components for custom labels
- Landmarks are automatically set for header, footer, and toolbar
- Panel close buttons include `aria-label="Close panel"`
- Resize handlers have `role="separator"` with proper `aria-orientation` and `aria-label`

---

## Best Practices

1. **Do**: Set an explicit height on the root Layout

```jsx
<Layout height="100dvh">
  {/* Content won't overflow */}
</Layout>
```

2. **Don't**: Nest multiple Layout.Content without explicit heights

```jsx
{/* This may cause layout issues */}
<Layout.Content>
  <Layout.Content>...</Layout.Content>
</Layout.Content>
```

3. **Do**: Use appropriate heading levels for accessibility

```jsx
<Layout.Header title="Page Title" level={1} />
```

4. **Do**: Provide close handlers when panels are closable

```jsx
<Layout.Panel isOpen={isOpen} onOpenChange={setIsOpen}>
  <Layout.PanelHeader
    isClosable
    title="Panel"
    onClose={() => setIsOpen(false)}
  />
</Layout.Panel>
```

5. **Do**: Use `hasTransition` for better UX when toggling panels

```jsx
<Layout.Panel hasTransition side="left" isOpen={isOpen}>
  {/* Smooth slide animation */}
</Layout.Panel>
```

---

## Architecture Notes

### Overflow-Safe Design

Layout uses a two-element architecture (wrapper + content). The wrapper has `overflow: visible` by default, allowing content to be visible outside its boundaries. Use `doNotOverflow` prop to apply `overflow: hidden` when you need to clip content. The inner element has absolute positioning with insets that adjust based on panel sizes.

### Panel Registration

Panels automatically register with the Layout context and report their sizes. This allows the main content area to adjust its insets accordingly, preventing content from being hidden behind panels.

### Nested Layouts

Each Layout.Content and panel header uses `LayoutContextReset` internally, which resets the layout context. This prevents nested Layouts from accidentally affecting parent layouts.

### Transitions

Panel transitions are disabled during drag operations and initial mount to prevent visual glitches. The `isReady` state ensures transitions only activate after the first paint.

---

## Suggested Improvements

- **Collapsible mode**: Add a mode where panels collapse to icons/mini state instead of fully hiding
- **Responsive breakpoints**: Automatically switch panels to dialog mode on smaller screens
- **Open state persistence**: Add `openStorageKey` for persisting panel open/closed state (size persistence is available via `sizeStorageKey`)
- **Split view**: Support for multiple resizable content areas (not just side panels)

---

## Related

- [Layout Guide](../../ComplexLayout.md) - Patterns and examples for building layouts
- [Dialog](../overlays/Dialog.md) - For modal panels
- [Item](./Item.md) - Used by PanelHeader

