# FlexiBoard

> The main container component of a board, managing the targets and widgets within it.

Source: https://www.flexiboards.dev/docs/components/board

Framework: Svelte

## FlexiBoard (component)

**Props**

| Name | Type | Description |
| --- | --- | --- |
| `controller` (bindable) | `FlexiBoardController \| undefined` | Optional. The controller managing this component's state and behaviour. Bind to it to access the component's imperative API. |
| `onfirstcreate` | `((instance: FlexiBoardController) => void) \| undefined` | Optional. Fires when the component's controller is first created. |
| `children` | `Snippet` | Required. The child content of the board, which should contain the inner FlexiTarget and FlexiWidget components. |
| `config` | `FlexiBoardConfiguration<ClassValue>` | Optional. The configuration object for the board. |
| `class` | `ClassValue` | Optional. The class names to apply to the board's root element. |
| `suspense` | `Snippet<[FlexiBoardSuspenseReason]>` | Optional. Fallback content shown while the board's server-rendered layout is provisional: a stored layout not yet imported, or an unconfirmed responsive breakpoint guess. It is server-rendered alongside the board and toggled by generated CSS, so it applies from the first paint. It unmounts once the layout is confirmed at hydration. |

```svelte
<script lang="ts">
	import { FlexiBoard, FlexiTarget } from '@flexiboards/svelte';
</script>

<FlexiBoard class="flex gap-4" config={{ widgetDefaults: { draggability: 'full' } }}>
	<FlexiTarget key="main">
		<!-- widgets go here -->
	</FlexiTarget>
</FlexiBoard>
```

## FlexiBoardController

You can access the controller via binding to the `controller` prop or using the `onfirstcreate` callback.

```svelte
<script lang="ts">
	import { FlexiBoard, type FlexiBoardController } from '@flexiboards/svelte';

	let board: FlexiBoardController | undefined = $state();
</script>

<FlexiBoard bind:controller={board}>
	<!-- targets go here -->
</FlexiBoard>
```

**Properties**

| Name | Type | Description |
| --- | --- | --- |
| `style` | `string` | The reactive styling to apply to the board's root element. |
| `ref` | `HTMLElement \| undefined` | The reactive DOM reference to the board's root element. |
| `breakpoint` (readonly) | `string` | The breakpoint that the board corresponds to, if the board is responsive. |
| `layoutPending` (readonly) | `boolean` | Whether the board's rendered layout is provisional: a `loadLayout` (or `loadLayouts`) is configured but hasn't run yet. True throughout a server render and during hydration until the stored layout is imported. Adapters expose it in the markup (`data-flexi-pending="layout"`) so a skeleton or veil can cover the stand-in layout. |
| `breakpointPending` (readonly) | `string \| null` | The breakpoint this render is assuming without confirmation, or null once it's real. Non-null only for a board under a ResponsiveFlexiBoard during a server render, where the rendered breakpoint is a guess. Adapters emit it as `data-flexi-pending="<key>"` (unless layoutPending takes priority) so a stylesheet can veil the board only when the viewport doesn't match the guess. |
| `currentWidgetAction` (readonly) | `WidgetAction \| null` | The move or resize the user is in the middle of, or null when idle. Reactive: read it during render to react to a drag starting and ending. |

**Methods**

| Name | Type | Description |
| --- | --- | --- |
| `moveWidget` | `(widget: FlexiWidgetController, from: FlexiTargetController \| undefined, to: FlexiTargetController) => void` | Moves an existing widget from one target to another. |
| `importLayout` | `(layout: FlexiLayout \| FlexiLayoutEnvelope) => void` | Imports a widget layout into the board: a bare layout, or the `{ version, layout }` envelope that `exportLayoutEnvelope()` returns. |
| `exportLayout` | `() => FlexiLayout` | Exports the current widget layout of the board. |
| `exportLayoutEnvelope` | `() => FlexiLayoutEnvelope` | Exports the layout with its format version, the shape to persist so a later release can migrate it on import. |
| `clear` | `() => void` | Deletes every widget in every target of this board. Fires `onWidgetDelete` per widget and `onLayoutChange` once. |

## FlexiBoardConfiguration

`FlexiBoard` accepts these options through `config`. See [Configuration reactivity](https://www.flexiboards.dev/docs/configuration#reactivity) for update behavior and initialization-only options.

For reactivity, give the `config` prop a reactive source (a proxy).

**Properties**

| Name | Type | Description |
| --- | --- | --- |
| `widgetDefaults` | `FlexiWidgetDefaults<ClassValue> \| undefined` | Optional. The default configuration for widgets within this board. |
| `targetDefaults` | `FlexiTargetDefaults \| undefined` | Optional. The default configuration for targets within this board. |
| `breakpoint` | `string \| undefined` | Optional. Optional breakpoint override. When this board is inside a ResponsiveFlexiBoard, the breakpoint is automatically inferred from the responsive controller's `currentBreakpoint`. You typically don't need to set this manually. If set outside of a ResponsiveFlexiBoard context, a warning will be logged. |
| `registry` | `Record<string, FlexiRegistryEntry<ClassValue>> \| undefined` | Optional. A registry of widget types, mapping type keys to shared widget configuration. Widgets reference an entry via their `type`. |
| `initialLayout` | `FlexiLayout \| undefined` | Optional. A layout to render from instead of the widgets declared in markup, as a plain value keyed by target. Applied during the initial render pass on both the server and the client, so a layout fetched in a server request handler (e.g. from a database) server-renders at its final positions with no pending window. Requires a `registry` to resolve each entry's `type`. Targets without an entry here fall back to their declared widgets. A configured `loadLayout` still runs on the client and overrides this. |
| `loadLayout` | `(() => 	\| FlexiLayout 	\| FlexiLayoutEnvelope 	\| FlexiWidgetLayoutEntry[] 	\| undefined) \| undefined` | Optional. Function to load an initial layout on mount. Called once when the board is ready. Not invoked during server rendering. Use `initialLayout` for layouts the server already has. |
| `onLayoutChange` | `((layout: FlexiLayout) => void) \| undefined` | Optional. Callback fired when the board's layout changes (widget moved, resized, added, or removed), whether by the user or through the controller API. Receives the committed layout in a microtask, before drop animations settle. Synchronous changes are batched into one notification. |
| `onWidgetGrab` | `((event: FlexiWidgetEvent) => void) \| undefined` | Optional. Called when the user picks a widget up (by pointer or keyboard). |
| `onWidgetDrop` | `((event: FlexiWidgetDropEvent) => void) \| undefined` | Optional. Called when a widget the user was moving or resizing lands in a target. Fires after the placement is committed, so the widget's `x`, `y`, `width`, `height` and `target` are already final. |
| `onWidgetCancel` | `((event: FlexiWidgetEvent) => void) \| undefined` | Optional. Called when the user cancels a move or resize (Escape, or releasing where nothing accepts the widget); the widget is back where it started. |
| `onWidgetDelete` | `((event: FlexiWidgetEvent) => void) \| undefined` | Optional. Called when a widget is deleted, by dropping it on a FlexiDelete or by calling `widget.delete()`. |
| `onWidgetResize` | `((event: FlexiWidgetEvent) => void) \| undefined` | Optional. Called when a resize the user was making commits. The widget's `width` and `height` are already final. |
| `onWidgetEnterTarget` | `((event: FlexiWidgetEvent) => void) \| undefined` | Optional. Called when a widget being moved is carried over a target, which then shows a drop preview for it. |
| `onWidgetLeaveTarget` | `((event: FlexiWidgetEvent) => void) \| undefined` | Optional. Called when a widget being moved leaves the target it was over. |
| `canDrop` | `((check: FlexiDropCheck) => boolean) \| undefined` | Optional. Decides whether a widget may be placed at a position. Called while the user hovers (so the drop preview can show a rejection) and again on release. Return false to refuse: the widget stays where it was. Placement rules the grid already enforces (bounds, collisions) run regardless. |
| `portalDropFlights` | `boolean \| undefined` | Optional. Hosts drop flights in the fixed, viewport-level portal instead of flying them inside the board. Reach for this when drops are released outside the board's box and must fly in across its edge without clipping under the board's overflow lock (e.g. a small hero board mid-page). Leave it off for scrollable boards: a portalled flight escapes the scroll container's clip and paints above surrounding chrome for its duration. Default: `false`. |
| `autoScroll` | `boolean \| undefined` | Optional. Scrolls the board's scrollable ancestors (the page included) while a drag or resize hovers within 48px of their visible edge. Turn it off for boards that sit on a page where a drag should never move the viewport (e.g. a marketing hero). An unexpected page scroll mid-drag reads as the board jumping. Default: `true`. |

### FlexiTargetDefaults

The default configuration for targets.

**Properties**

| Name | Type | Description |
| --- | --- | --- |
| `rowSizing` | `(string \| (({ target, grid }: { target: FlexiTargetController; grid: FlexiGrid }) => string))` | Optional. The value inside the target's `grid-template-rows` `repeat()` function. |
| `columnSizing` | `(string \| (({ target, grid }: { target: FlexiTargetController; grid: FlexiGrid }) => string))` | Optional. The value inside the target's `grid-template-columns` `repeat()` function. |
| `layout` | `TargetLayout` | Optional. The layout algorithm and parameters to use for the target grid. |

### Interaction callbacks

`onWidgetGrab`, `onWidgetDrop`, `onWidgetResize`, `onWidgetCancel`, `onWidgetDelete`, `onWidgetEnterTarget` and `onWidgetLeaveTarget` receive these events. `canDrop` receives a `FlexiDropCheck` and returns whether the placement is allowed; see [Reacting to interactions](https://www.flexiboards.dev/docs/controllers#reacting-to-interactions) for when each fires.

#### FlexiWidgetEvent

**Properties**

| Name | Type | Description |
| --- | --- | --- |
| `widget` | `FlexiWidgetController` | Required. |
| `target` | `FlexiTargetController` | Optional. The target the widget is in or over. Undefined when it is over none (e.g. a cancelled adder drag). |

#### FlexiWidgetDropEvent

**Properties**

| Name | Type | Description |
| --- | --- | --- |
| `widget` | `FlexiWidgetController` | Required. |
| `sourceTarget` | `FlexiTargetController` | Optional. The target the widget was picked up from. Undefined for a widget added through an adder. |
| `target` | `FlexiTargetController` | Required. The target the widget landed in. |

#### FlexiDropCheck

**Properties**

| Name | Type | Description |
| --- | --- | --- |
| `widget` | `FlexiWidgetController` | Required. |
| `target` | `FlexiTargetController` | Required. |
| `x` | `number` | Required. |
| `y` | `number` | Required. |
| `width` | `number` | Required. |
| `height` | `number` | Required. |

### FlexiWidgetDefaults

The default configuration for widgets.

**Properties**

| Name | Type | Description |
| --- | --- | --- |
| `draggability` | `'none' \| 'movable' \| 'full' \| undefined` | Optional. The draggability of the widget. Default: `full`. |
| `resizability` | `'none' \| 'horizontal' \| 'vertical' \| 'both' \| undefined` | Optional. The resizability of the widget. Default: `none`. |
| `snippet` | `(Snippet<[{ widget: FlexiWidgetController }]>)` | Optional. The render function used for this widget's content. |
| `component` | `(Component)` | Optional. The component that is rendered by this widget. |
| `componentProps` | `Record<string, any> \| undefined` | Optional. The props applied to the component rendered, if it has one. |
| `className` | `(ClassValue \| ((widget: FlexiWidgetController) => ClassValue)) \| undefined` | Optional. The class names to apply to this widget. |
| `transition` | `FlexiWidgetTransitionConfiguration \| undefined` | Optional. The transition configuration for this widget. |
| `grabTrigger` | `FlexiWidgetTriggerConfiguration \| undefined` | Optional. The configuration for how pointer events should trigger a grab event on the widget. E.g. a long press. |
| `resizeTrigger` | `FlexiWidgetTriggerConfiguration \| undefined` | Optional. The configuration for how pointer events should trigger a resize event on the widget. E.g. a long press. |
| `minWidth` | `number \| undefined` | Optional. The minimum width of the widget in units. Defaults to 1, cannot be less than 1. |
| `minHeight` | `number \| undefined` | Optional. The minimum height of the widget in units. Defaults to 1, cannot be less than 1. |
| `maxWidth` | `number \| undefined` | Optional. The maximum width of the widget in units. Defaults to Infinity, cannot be less than 1. |
| `maxHeight` | `number \| undefined` | Optional. The maximum height of the widget in units. Defaults to Infinity, cannot be less than 1. |

## FlexiLayout

The value returned by `exportLayout()` and accepted by `importLayout()`, `initialLayout`, and `loadLayout`. It maps each target's `key` to an array of entries. See [Exporting & Importing](https://www.flexiboards.dev/docs/guides/exporting-importing-boards).

### FlexiWidgetLayoutEntry

**Properties**

| Name | Type | Description |
| --- | --- | --- |
| `id` | `string` | Optional. A stable identifier for this widget. Always present in an export: the id you gave the widget, or a generated one. Round-trips through import. |
| `type` | `string` | Optional. The registry key that says how to render this widget. Exported even when absent, so no widget's position is lost; on import, entries without a type are skipped, since nothing says how to render them. |
| `x` | `number` | Required. The column the widget starts at, zero-indexed. |
| `y` | `number` | Required. The row the widget starts at, zero-indexed. |
| `width` | `number` | Required. The width of the widget in grid units. |
| `height` | `number` | Required. The height of the widget in grid units. |
| `metadata` | `Record<string, any>` | Optional. Custom serialisable data attached to the widget, preserved through export and import. |

### FlexiRegistryEntry

An entry in the board's `registry`, keyed by widget `type`. Its properties are widget defaults applied to every widget of that type.

**Properties**

| Name | Type | Description |
| --- | --- | --- |
| `draggability` | `'none' \| 'movable' \| 'full' \| undefined` | Optional. The draggability of the widget. Default: `full`. |
| `resizability` | `'none' \| 'horizontal' \| 'vertical' \| 'both' \| undefined` | Optional. The resizability of the widget. Default: `none`. |
| `snippet` | `(Snippet<[{ widget: FlexiWidgetController }]>)` | Optional. The render function used for this widget's content. |
| `component` | `(Component)` | Optional. The component that is rendered by this widget. |
| `componentProps` | `Record<string, any> \| undefined` | Optional. The props applied to the component rendered, if it has one. |
| `className` | `(ClassValue \| ((widget: FlexiWidgetController) => ClassValue)) \| undefined` | Optional. The class names to apply to this widget. |
| `transition` | `FlexiWidgetTransitionConfiguration \| undefined` | Optional. The transition configuration for this widget. |
| `grabTrigger` | `FlexiWidgetTriggerConfiguration \| undefined` | Optional. The configuration for how pointer events should trigger a grab event on the widget. E.g. a long press. |
| `resizeTrigger` | `FlexiWidgetTriggerConfiguration \| undefined` | Optional. The configuration for how pointer events should trigger a resize event on the widget. E.g. a long press. |
| `minWidth` | `number \| undefined` | Optional. The minimum width of the widget in units. Defaults to 1, cannot be less than 1. |
| `minHeight` | `number \| undefined` | Optional. The minimum height of the widget in units. Defaults to 1, cannot be less than 1. |
| `maxWidth` | `number \| undefined` | Optional. The maximum width of the widget in units. Defaults to Infinity, cannot be less than 1. |
| `maxHeight` | `number \| undefined` | Optional. The maximum height of the widget in units. Defaults to Infinity, cannot be less than 1. |

## Accessibility

The board renders as `role="application"`, described by a visually hidden instructions element, and carries `aria-busy` while a layout is [pending](https://www.flexiboards.dev/docs/guides/server-side-rendering). It also hosts the `aria-live` announcer that reports grabs, resizes, releases, and rejected drops. See [Accessibility](https://www.flexiboards.dev/docs/accessibility).
