# 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.

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

Framework: Svelte

## FlexiGrab (component)

**Props**

| Name | Type | Description |
| --- | --- | --- |
| `children` | `Snippet<[{ widget: FlexiWidgetController }]>` | Optional. The content of the handle. Receives the surrounding widget's controller. |
| `class` | `ClassValue` | Optional. 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'`.

Example: Grab handle

```svelte
<script lang="ts">
	import { FlexiBoard, FlexiTarget, FlexiWidget, FlexiGrab } from '@flexiboards/svelte';
	import GripVertical from 'lucide-svelte/icons/grip-vertical';
</script>

<FlexiBoard class="w-72 rounded-xl border p-6 lg:w-96">
	<FlexiTarget
		class="gap-3"
		config={{ layout: { type: 'flow', flowAxis: 'row', placementStrategy: 'append' } }}
	>
		{#each ['Only the handle drags me', 'Select my text freely'] as label}
			<FlexiWidget
				class={(widget) => [
					'bg-muted flex items-center gap-3 rounded-lg px-3 py-2',
					widget.isShadow && 'opacity-50'
				]}
			>
				<FlexiGrab class="hover:bg-background rounded p-1">
					<GripVertical class="size-4" />
					<span class="sr-only">Move widget</span>
				</FlexiGrab>
				<span>{label}</span>
			</FlexiWidget>
		{/each}
	</FlexiTarget>
</FlexiBoard>
```

`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:

```svelte
<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](https://www.flexiboards.dev/docs/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.
