v1.0
Primitive API / Page 04·04

FlexiGrab

A grab handle for a widget. Use it when only part of a widget should start a drag, leaving the rest free for buttons, links, and text selection.

FlexiGrab (component)

Props
NameDescription
children
Optional
Snippet<[{ widget: FlexiWidgetController }]>

The content of the handle. Receives the surrounding widget's controller.

class
Optional
ClassValue

Classes applied to the rendered button.

FlexiGrab renders a button inside a FlexiWidget. Once a widget contains at least one FlexiGrab, only its grab handles start a drag; pointer events elsewhere on the widget behave normally. The button is disabled while the widget’s draggability is not 'full'.

Svelte Grab handle
Press Enter to grab or resize widgets. Once grabbed, use Arrow keys to move/resize the widget, Enter to confirm the action, or Esc to cancel it.
Only the handle drags me
Select my text freely

FlexiGrab has no controller of its own. Inside its content you receive the surrounding widget’s controller, so the handle can reflect the widget’s state:

<FlexiGrab>
	{#snippet children({ widget })}
		<GripVertical class={widget.isGrabbed ? 'text-primary' : undefined} />
	{/snippet}
</FlexiGrab>

Accessibility

  • The handle is a native button, so it is focusable with Tab and disabled when the widget cannot be grabbed.
  • Give it a text label. An icon-only handle should contain a visually hidden span (for example, Tailwind’s sr-only) reading “Move widget”.
  • Once a widget has a grab handle, the widget itself is no longer focusable, and keyboard grabbing moves to the handle: Enter grabs, the arrow keys move, Enter drops, Escape cancels. See Accessibility for the full keyboard model.

Gotchas

  • A FlexiGrab must be rendered inside a FlexiWidget. Outside one, it throws.
  • The handle sets touch-action: none on itself so touch drags start immediately. Keep it small, or scrolling on touch devices becomes hard when a finger lands on it.