FlexiWidget
A component, such as a tile, that lives inside a target. You can move a widget within its target or to another target.
FlexiWidget (component)
| Name | Description |
|---|---|
controller Optional Bindable FlexiWidgetController | undefined | The controller managing this component's state and behaviour. Bind to it to access the component's imperative API. |
onfirstcreate Optional ((instance: FlexiWidgetController) => void) | undefined | Fires when the component's controller is first created. |
component Optional (Component) | The component that is rendered by this widget. |
draggability Optional 'none' | 'movable' | 'full' | undefined | The draggability of the widget. Default: |
resizability Optional 'none' | 'horizontal' | 'vertical' | 'both' | undefined | The resizability of the widget. Default: |
componentProps Optional Record<string, any> | undefined | The props applied to the component rendered, if it has one. |
transition Optional FlexiWidgetTransitionConfiguration | undefined | The transition configuration for this widget. |
grabTrigger Optional FlexiWidgetTriggerConfiguration | undefined | The configuration for how pointer events should trigger a grab event on the widget. E.g. a long press. |
resizeTrigger Optional FlexiWidgetTriggerConfiguration | undefined | The configuration for how pointer events should trigger a resize event on the widget. E.g. a long press. |
minWidth Optional number | undefined | The minimum width of the widget in units. Defaults to 1, cannot be less than 1. |
minHeight Optional number | undefined | The minimum height of the widget in units. Defaults to 1, cannot be less than 1. |
maxWidth Optional number | undefined | The maximum width of the widget in units. Defaults to Infinity, cannot be less than 1. |
maxHeight Optional number | undefined | The maximum height of the widget in units. Defaults to Infinity, cannot be less than 1. |
id Optional string | undefined | A stable identifier for this widget, used for persistence and layout import/export. Read when the widget is created. |
type Optional string | undefined | The registry key used when creating this widget. Changing the prop does not recreate it. |
x Optional number | undefined | The starting column (x-coordinate) of the widget. After creation, use moveTo() to move it. |
y Optional number | undefined | The starting row (y-coordinate) of the widget. After creation, use moveTo() to move it. |
width Optional number | undefined | The initial width of the widget in grid units. Changing the prop does not resize an existing widget. |
height Optional number | undefined | The initial height of the widget in grid units. Changing the prop does not resize an existing widget. |
metadata Optional Record<string, any> | undefined | Arbitrary metadata associated with this widget, carried through layout export/import. |
class Optional Bindable (ClassValue | ((widget: FlexiWidgetController) => ClassValue)) | The class names to apply to this widget. Either a class value, or a function deriving one from the widget's state. |
children Optional Bindable (Snippet<[{ widget: FlexiWidgetController }]>) | The content rendered within the widget. |
Widget content is rendered either from children, which receives the widget’s controller, or from the component prop (with componentProps), or both.
<script lang="ts">
import { FlexiWidget } from '@flexiboards/svelte';
</script>
<FlexiWidget
draggability="full"
resizability="both"
width={2}
height={1}
class={(widget) => ['rounded-lg border p-4', widget.isGrabbed && 'opacity-50']}
>
{#snippet children({ widget })}
<span>{widget.width} × {widget.height}</span>
{/snippet}
</FlexiWidget> Adding widgets later
You can mount new FlexiWidget declarations after the target has loaded. Each declaration uses the same placement rules as target.createWidget(): flow grids follow their placement strategy, and free-form grids check coordinates, dimensions, and collisions.
<script lang="ts">
import { FlexiSortable, FlexiWidget } from '@flexiboards/svelte';
let notes = $state([1]);
</script>
<div class="w-full space-y-3">
<button
type="button"
class="rounded border px-3 py-2"
onclick={() => (notes = [...notes, notes.length + 1])}>Add note</button
>
<FlexiSortable class="gap-2">
{#each notes as note (note)}
<FlexiWidget id={\`note-\$\{note}\`} class="rounded border p-3">Note {note}</FlexiWidget>
{/each}
</FlexiSortable>
</div>Keep list keys stable. A declaration registers once per mount; rerendering it updates its props without adding another widget. The board owns the created widget, so removing its declaration does not delete it. Use widget.delete() or target.clear() to remove widgets.
An accepted addition fires onfirstcreate and reports the new layout through onLayoutChange. If placement fails, the widget is not created and a warning explains the failure. Freeing space later does not automatically retry a rejected declaration.
FlexiWidgetController
You can access the controller by binding to the controller prop, from the onfirstcreate callback, or from the children snippet parameter. Inside a component rendered by the component prop, call getFlexiwidgetCtx().
<script lang="ts">
import { getFlexiwidgetCtx } from '@flexiboards/svelte';
const widget = getFlexiwidgetCtx();
</script>
<span>{widget.isGrabbed ? 'Moving' : 'Idle'}</span> Use the FlexiWidgetController to read widget state directly.
| Name | Description |
|---|---|
target FlexiTargetController | undefined | The target this widget is under. Undefined until the widget is dropped in the board. |
ref HTMLElement | undefined | The DOM element bound to this widget. |
isShadow boolean | Whether this widget is a shadow dropzone widget. |
isGrabbed Readonly boolean | Whether this widget is grabbed. |
isResizing Readonly boolean | Whether this widget is being resized. |
dropRejected boolean | Whether the widget is being grabbed or resized over a target that cannot accept it where it is: the drop would be rejected on release and the widget would return to where it came from. |
isInterpolating Readonly boolean | Whether the widget is currently animating to a new position or size, e.g. mid drop flight. Useful for styling that should only apply at rest, such as hover effects that would otherwise fire as the widget lands under the pointer. |
currentAction WidgetAction | null | When the widget is being grabbed, this contains information that includes its position, size and offset. When this is null, the widget is not being grabbed. |
draggable Readonly boolean | Whether the widget can move at all: its `draggability` is not `'none'`. Read-only; set `draggability` to change it. |
draggability 'none' | 'movable' | 'full' | The draggability of the widget. |
isGrabbable Readonly boolean | Whether the widget can be grabbed. |
isMovable Readonly boolean | Whether the widget can be moved. |
resizability 'none' | 'horizontal' | 'vertical' | 'both' | The resizability of the widget. |
resizable Readonly boolean | Whether the widget is resizable. |
width Readonly number | The width in units of the widget. |
height Readonly number | The height in units of the widget. |
component (Component) | undefined | The component that is rendered by this widget. |
componentProps Record<string, any> | undefined | The props applied to the component rendered, if it has one. |
snippet (Snippet<[{ widget: FlexiWidgetController }]>) | undefined | The render function used for this widget's content. |
className unknown | The class name that is applied to this widget. |
x Readonly number | Gets the column (x-coordinate) of the widget. This value is readonly and is managed by the target. |
y Readonly number | Gets the row (y-coordinate) of the widget. This value is readonly and is managed by the target. |
metadata Record<string, any> | undefined | The metadata associated with this widget, if any. |
grabTrigger Readonly FlexiWidgetTriggerConfiguration | Gets the configuration for how pointer events should trigger widget grabs (either on the widget directly or on a grabber). |
resizeTrigger Readonly FlexiWidgetTriggerConfiguration | Gets the configuration for how pointer events should trigger widget resizing on a resizer. |
transitionConfig Readonly FlexiWidgetTransitionConfiguration | Gets the transition configuration for this widget. |
hasGrabbers Readonly boolean | Whether the widget has any grabbers attached. |
hasResizers Readonly boolean | Whether the widget has any resizers attached |
isBeingDropped boolean | Whether the widget is currently being dropped after a drag operation. |
minWidth Readonly number | The minimum width of the widget in units. |
minHeight Readonly number | The minimum height of the widget in units. |
maxWidth Readonly number | The maximum width of the widget in units. |
maxHeight Readonly number | The maximum height of the widget in units. |
userProvidedId Readonly string | undefined | The user-provided stable identifier for this widget, if any. This is used for persistence and layout import/export. |
type Readonly string | undefined | The type of this widget (registry key for looking up configuration). |
| Name | Description |
|---|---|
delete () => void | Deletes this widget from its target and board. Fires the board's `onWidgetDelete` and `onLayoutChange`. |
moveTo (options: { target?: FlexiTargetController; x?: number; y?: number }) => boolean | Moves this widget through the controller API, with no user interaction: to a position in its own target, to another target (at a position, or wherever that target's grid puts it), or both. Runs the grid's placement rules but not `canDrop`, which is for user drops. Fires `onLayoutChange`. |
FlexiWidgetConfiguration
FlexiWidget accepts configuration as props. Changes to rendering, metadata, interaction options, size limits, and transitions update the existing widget. id, type, x, y, width, and height initialize the widget; changing those props does not recreate or reposition it. Use moveTo() for movement, or import a layout to replace widget positions and sizes. See Configuration reactivity.
| Name | Description |
|---|---|
draggability Optional 'none' | 'movable' | 'full' | undefined | The draggability of the widget. Default: |
resizability Optional 'none' | 'horizontal' | 'vertical' | 'both' | undefined | The resizability of the widget. Default: |
snippet Optional (Snippet<[{ widget: FlexiWidgetController }]>) | The render function used for this widget's content. |
component Optional (Component) | The component that is rendered by this widget. |
componentProps Optional Record<string, any> | undefined | The props applied to the component rendered, if it has one. |
className Optional (ClassValue | ((widget: FlexiWidgetController) => ClassValue)) | undefined | The class names to apply to this widget. |
transition Optional FlexiWidgetTransitionConfiguration | undefined | The transition configuration for this widget. |
grabTrigger Optional FlexiWidgetTriggerConfiguration | undefined | The configuration for how pointer events should trigger a grab event on the widget. E.g. a long press. |
resizeTrigger Optional FlexiWidgetTriggerConfiguration | undefined | The configuration for how pointer events should trigger a resize event on the widget. E.g. a long press. |
minWidth Optional number | undefined | The minimum width of the widget in units. Defaults to 1, cannot be less than 1. |
minHeight Optional number | undefined | The minimum height of the widget in units. Defaults to 1, cannot be less than 1. |
maxWidth Optional number | undefined | The maximum width of the widget in units. Defaults to Infinity, cannot be less than 1. |
maxHeight Optional number | undefined | The maximum height of the widget in units. Defaults to Infinity, cannot be less than 1. |
id Optional string | undefined | A stable identifier for this widget, used for persistence and layout import/export. Read when the widget is created. |
type Optional string | undefined | The registry key used when creating this widget. Changing the prop does not recreate it. |
x Optional number | undefined | The starting column (x-coordinate) of the widget. After creation, use moveTo() to move it. |
y Optional number | undefined | The starting row (y-coordinate) of the widget. After creation, use moveTo() to move it. |
width Optional number | undefined | The initial width of the widget in grid units. Changing the prop does not resize an existing widget. |
height Optional number | undefined | The initial height of the widget in grid units. Changing the prop does not resize an existing widget. |
metadata Optional Record<string, any> | undefined | Arbitrary metadata associated with this widget, carried through layout export/import. |
FlexiWidgetTransitionConfiguration
The transition property of a widget’s configuration (or of widgetDefaults). See the Transitions guide for presets and the animation adapters.
| Name | Description |
|---|---|
move Optional ({ duration?: number; easing?: string } | AnimationAdapter) | Plays when a widget moves between cells of a grid, including when it is pushed aside by another widget. Omit to play no animation. |
drop Optional ({ duration?: number; easing?: string } | AnimationAdapter) | Plays when a grabbed widget is released and settles into its cell. Omit to play no animation. |
resize Optional ({ duration?: number; easing?: string } | AnimationAdapter) | Plays when a widget is released from a resize and settles at its new size. Omit to play no animation. |
Accessibility
Each placed widget renders as role="gridcell" with one-based aria-colindex and aria-rowindex, plus aria-colspan and aria-rowspan. The held widget temporarily uses role="group"; its preview is hidden and inert. The data-flexi-widget attribute remains present in every state. A grabbable widget is in the tab order unless it contains a FlexiGrab, in which case the handle is.
| Key | Effect |
|---|---|
| Enter | Grabs the focused widget; while grabbed, drops it. |
| Arrow keys | Moves the grabbed widget. Shift for larger steps, Ctrl / Cmd for finer ones. |
| Escape | Cancels a grab or resize. |
Grabs, resizes, releases, and rejected drops are announced through the board’s live region. Styling the isGrabbed, isShadow, and dropRejected states is up to you; see Widget Rendering. Full details in Accessibility.