Files
2026-09-04 09:04:51 -07:00

118 lines
4.1 KiB
Plaintext

---
title: Z-Index & Stacking
description: How Gui automatically stacks overlays and floating content
name: z-index
---
Gui includes an automatic stacking system that ensures overlays like dialogs, popovers, sheets, and tooltips layer correctly without manual z-index management.
## How It Works
When you open overlay components, Gui automatically assigns z-index values so that:
- **Later-opened content appears above earlier content** - Open two dialogs? The second one stacks above the first.
- **Nested content appears above its parent** - A tooltip inside a dialog automatically renders above the dialog.
- **Closing restores order** - When content closes, z-index values are reclaimed.
This means you typically don't need to think about z-index at all.
## When to Set zIndex
Only set `zIndex` when you need to override the automatic stacking. Common cases:
- **Fixed headers/footers** - If you have a sticky header at `z-index: 100`, overlays need to appear above it (they do by default).
- **Third-party libraries** - If integrating with libraries that use high z-index values.
- **Custom stacking requirements** - When you need specific layering that differs from open-order.
```tsx
// Only if you need to override automatic stacking
<Dialog zIndex={200000}>...</Dialog>
```
## Component Defaults
All overlay components use the automatic stacking system. Here's where to set `zIndex` if needed:
| Component | Where to set zIndex |
| ------------------------------- | ----------------------------------- |
| [Dialog](/ui/dialog) | `<Dialog zIndex={...}>` |
| [AlertDialog](/ui/alert-dialog) | `<AlertDialog zIndex={...}>` |
| [Sheet](/ui/sheet) | `<Sheet zIndex={...}>` |
| [Select](/ui/select) | `<Select zIndex={...}>` |
| [Popover](/ui/popover) | `<Popover zIndex={...}>` |
| [Tooltip](/ui/tooltip) | `<Tooltip zIndex={...}>` |
| [Menu](/ui/menu) | `<Menu.Portal zIndex={...}>` |
| [ContextMenu](/ui/context-menu) | `<ContextMenu.Portal zIndex={...}>` |
| [Toast](/ui/toast) | Via `ToastViewport` |
## Stacking Hierarchy
By default, components stack in this order (lowest to highest):
1. **Popover, Tooltip, Menu** - Pure auto-stacking, starts around z-index 5001
2. **Dialog, AlertDialog, Select, Sheet** - Use a higher base (100000+) to ensure they appear above most UI
Within each category, **mount order determines stacking** - open a popover, then another, the second is on top.
## Nested Stacking
Nested floating elements automatically stack above their parent:
```tsx
<Dialog>
<Dialog.Content>
{/* This tooltip will appear above the dialog */}
<Tooltip>
<Tooltip.Trigger>
<Button>Hover me</Button>
</Tooltip.Trigger>
<Tooltip.Content>I appear above the dialog!</Tooltip.Content>
</Tooltip>
</Dialog.Content>
</Dialog>
```
The system tracks parent-child relationships through React context, so nested portals always stack correctly.
## Technical Details
The stacking system uses two mechanisms:
### Horizontal Stacking (Siblings)
When multiple overlays open at the same level, each gets an incrementing z-index:
- First dialog: 105001
- Second dialog: 105002
- Third dialog: 105003
### Vertical Stacking (Nested)
When content opens inside another portal, it reads the parent's z-index from context and adds 1:
- Dialog opens at 105001
- Popover inside dialog: 105002
- Tooltip inside that popover: 105003
This ensures nested content is always visible above its parent, but sibling content opened later can still stack above.
## Portal Component
The [Portal](/ui/portal) component powers this stacking system. If building custom overlay components, you can use Portal's `stackZIndex` prop:
```tsx
import { Portal } from '@hanzo/gui'
// Enable automatic stacking
<Portal stackZIndex>
{/* content */}
</Portal>
// Or use a high base value (like Dialog does)
<Portal stackZIndex={100000}>
{/* content */}
</Portal>
```
See the [Portal documentation](/ui/portal) for more details.