# DashboardGridOptions

Import it from `@grafloria/element`.

```ts
interface DashboardGridOptions
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `columns?` | `number` |  | Column count (default 12). With `responsive`, the starting/maximum count. |
| `rtl?` | `boolean` |  | RIGHT-TO-LEFT board. Cells are unchanged — x=0 is still the first column — but it renders at the board's RIGHT edge and columns run leftwards. Purely a pixel-mapping concern: the engine, the cells and every saved layout are direction-agnostic. |
| `responsive?` | `DashboardResponsiveOptions` |  | Derive the column count from the board's width (see the interface). |
| `onColumnsChange?` | `(columns: number, previous: number) => void` |  | Fires after a responsive (or programmatic) column-count change. |
| `gap?` | `number` |  | Gap between cells, px (default 12). |
| `padding?` | `number` |  | Board padding, px (default = gap). |
| `sizing?` | `'fit' \| 'grow'` |  | Sizing mode (default 'fit' — the user decision recorded in the plan). |
| `baseRowHeight?` | `number` |  | 'grow' row height, px (default 110). |
| `minRowHeight?` | `number` |  | 'fit' row-height floor, px (default 28). |
| `designHeight?` | `number` |  | The board's design height (default: the group's height at bind time). 'fit' pins the frame to it; 'grow' never shrinks the frame below it. |
| `float?` | `boolean` |  | Engine float mode (default false → gravity packs upward). |
| `maxRows?` | `number` |  | Engine row bound (see GridPackOptions.maxRows). A nested strip like the KPI section passes 1: its DESIGN is one row, so height growth and pushes that would spill a sibling downward are refused (siblings shift along the row instead), and the strip can never be squeezed. |
| `escalate?` | `boolean` |  | Nested boards only. `true` (default): a child pulled clearly past the bound GROWS the container's slab in the parent (height escalation). `false`: the pane is the bound — the pull is refused where it stands, the container's `sizing: 'fit'`. |
| `dragOut?` | `'remove' \| 'cancel'` |  | What dragging a tile OUT of the board means (default 'cancel' — the tile snaps back on release). 'remove' dims the ghost outside the board and a release outside calls `onRemoveRequest` — deletion stays on the page's atomic command path. |
| `removeZone?` | `(screen: { x: number; y: number }, world: { x: number; y: number }) => boolean` |  | With dragOut:'remove', restrict deletion to an EXPLICIT drop zone (the page passes "over the palette" — gridstack web2's trash semantics). Outside the zone a release snaps home instead: a 60px overshoot past the frame edge must never destroy a widget (live parity review — the plan prototype clamps at its edges and cannot delete at all). |
| `onRemoveRequest?` | `(nodeId: string, displaced: Command[]) => void \| Promise<void>` |  | Page hook for drag-out removal: execute ONE undoable batch that removes `nodeId` AND applies `displaced` (the survivors' cell commits, so undo restores the exact board). |
| `onDropIn?` | `(node: NodeModel, cell: CellRect, displaced: Command[], target: { boardId: string }) => void \| Promise<void>` |  | Page hook for palette drag-in release: add `node` (already carrying `cell` in its gridItem) to `target.boardId` — this view, or a page or section the chip was dropped into (tile first, step 4a) — through the page's command path, folding `displaced` into the same batch. |
| `onMemberLeaving?` | `(memberId: string) => Command[]` |  | A member is about to LEAVE this board through a gesture (moved into another board, made a tab of its own). Answers the commands that follow it in the same batch — a tab page emptied by the move closes. |
| `onMemberMoving?` | `(memberId: string, fromBoardId: string, toBoardId: string) => Command[]` |  | A member CONTAINER is moving from this board to another by a gesture (tile first, 4b-ii). Answers the commands that carry the host's own bookkeeping for it — the spec entry, the registry — in the same batch. |
| `tabDrop?` | `TabDropHooks` |  | A widget dragged over a tab STRIP becomes a new tab there: the hooks that hit-test, mark and commit it. |
| `onGesture?` | `(e: { type: 'commit' \| 'cancel' \| 'remove' \| 'drop-in'; kind: 'move' \| 'resize' \| 'palette'; nodeId: string; changed: boolean; }) => void` |  | Fires after commits/cancels/removals so the page can refocus/refit/flash. |
| `onSelect?` | `(id: string \| undefined) => void` |  | The selection on this board changed: the selected member — a widget or a SECTION (container) — or undefined. |
| `renderCaption?` | `(sectionId: string, host: HTMLElement) => void` |  | SECTION CAPTIONS (0.4.22). Paint a member section's caption band yourself: the band is handed over empty, sized and themed, and keeps its press rules. Default: the kit's icon · text · subtitle · ⓘ · actions. |
| `onCaptionAction?` | `(sectionId: string, actionId: string) => void` |  | A press on a caption action button (see `SectionCaptionOptions.actions`). |
| `resizeHandles?` | `boolean` |  |  |
| `fluid?` | `boolean` |  | FLUID board: the group's frame follows the CANVAS CONTAINER — width always, and height too in 'fit' — so the dashboard is laid out at real CSS pixels like every other grid library, never as a picture the camera scales (review D1: a 900-px viewport drew 30-px KPI figures at 18 px). The binder owns the ResizeObserver; `sync()` re-reads the container as well. |
| `overflow?` | `'bounded' \| 'scroll'` |  | What FIT mode does past its row floor. 'bounded' (default): the design height is a CAPACITY — a drop, resize or add that would need one row too many is refused (the engine's `capacity`), visibly, at design time. 'scroll': no bound; the frame extends to hold the rows at the floor height so nothing paints outside it, and the canvas pans. |
| `static?` | `boolean` |  | STATIC board (gridstack's `staticGrid`): the pointer can neither drag nor resize and no handles are injected; the API (moveTo/resizeTo, adds, undo) still works. The viewer's mode — see `setStatic` for the live switch. |
| `nesting?` | `number` |  | NESTING POLICY (tile first, step 2): the deepest board a DROP may enter, counting a view as 0 — a widget into a section is 1, into a section inside a tab page is 2. Deeper containers are opaque to a drag: the pointer over them means a cell on their parent board (or beside them). Unbounded by default. |
| `dragHandle?` | `DragHandleOption` |  | DRAG HANDLE (DevExpress drags an item by its caption; gridstack's `handle`). `true` — the CAPTION STRIP is the handle (the header shows grip dots); a selector string — your own element inside the host; a `{ grip: true }` object — a dedicated GRIP the kit paints, positioned left / center / right and, for the top edge, `inside` the header band or `outside` as a tab above the card (the DevExpress … |
| `squeeze?` | `boolean` |  | FIT AND THE ROW FLOOR. `true` (default): a bounded fit board holds as many rows as fit at `minRowHeight` — a gesture that needs another row SQUEEZES every row toward the floor, and is refused only when even that is not enough. |
