# Widget rendering

> Learn about approaches to rendering widgets in Flexiboards.

Source: https://www.flexiboards.dev/docs/widget-rendering

Framework: Svelte

`FlexiWidget` registers content in a target. Flexiboards handles placement and interaction; your content defines what the widget displays. This demo uses the [docs example styling](https://www.flexiboards.dev/docs/overview#example-styling):

Example: Styling by state

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

<FlexiBoard class="size-72 rounded-xl border p-8 lg:size-96">
	<FlexiTarget
		class="h-full w-full gap-4"
		containerClass="h-full w-full"
		config={{
			rowSizing: 'minmax(0, 1fr)',
			layout: { type: 'free', minRows: 2, minColumns: 2, maxRows: 2, maxColumns: 2 },
			widgetDefaults: {
				className: (widget) => [
					'flex items-center justify-center rounded-lg bg-primary text-primary-foreground',
					widget.isShadow && 'opacity-50',
					widget.isGrabbed && 'animate-pulse',
					widget.dropRejected && 'bg-destructive'
				]
			}
		}}
	>
		<FlexiWidget x={0} y={0}>
			{#snippet children({ widget })}
				{widget.isGrabbed ? 'Grabbed' : 'Drag me'}
			{/snippet}
		</FlexiWidget>
		<FlexiWidget
			x={1}
			y={1}
			draggability="none"
			class="bg-muted text-foreground flex items-center justify-center rounded-lg"
		>
			Fixed
		</FlexiWidget>
	</FlexiTarget>
</FlexiBoard>
```

Drag the first widget: its label changes while grabbed, its shadow in the grid is translucent, and it turns red over the fixed widget because that drop would be rejected.

## Children-based

These declaration excerpts belong inside an existing target. Keep the imports and board setup from the opening example.

Pass a `children` [snippet](https://svelte.dev/docs/svelte/snippet) to render content inline. Any elements or components you write become the content markup of your widget, like any other container component.

Flexiboards passes parameters into the `children` snippet, which you can read or ignore:

```svelte
<!-- Without using the parameters (i.e. implicit children snippet) -->
<FlexiWidget>I'm a FlexiWidget!</FlexiWidget>

<!-- With the parameters (e.g. get widget reactive data) - we discuss component and componentProps later -->
<FlexiWidget>
	{#snippet children({ widget })}
		I'm a FlexiWidget at ({widget.x}, {widget.y})!
	{/snippet}
</FlexiWidget>
```

The first example needs no data from the `widget` controller, so it takes no parameters. The second reads the reactive `x` and `y` properties on the controller and shows them; the [FlexiWidget](https://www.flexiboards.dev/docs/components/widget) API lists the other properties you can read this way.

Use a component when several widgets share a renderer, or when a registry selects content for imported widgets.

## Component-based

Set `component` to an imported Svelte component. This declaration excerpt assumes `my-component.svelte` exists and belongs inside your existing target:

```svelte
<script>
	import { FlexiWidget } from '@flexiboards/svelte';
	import MyComponent from './my-component.svelte';
</script>

<FlexiWidget component={MyComponent} />
```

Pass props to the component with `componentProps`. A `children` snippet takes precedence over `component`. To wrap the configured component, render `widget.component` with `widget.componentProps` inside that snippet; Flexiboards does not render both automatically.

In this scenario the `widget` controller is not passed as a prop on the component. Instead, use the `getFlexiwidgetCtx` helper function to get the context of the widget:

```svelte
<!-- my-component.svelte -->
<script>
	import { getFlexiwidgetCtx } from '@flexiboards/svelte';

	const widget = getFlexiwidgetCtx();
</script>

<span>Column {widget.x}, row {widget.y}</span>
```

This uses the [Svelte Context API](https://svelte.dev/docs/svelte/context) under the hood, so call it from the top level of the component, or from a function that the top level calls.

Any Svelte component rendered inside of the FlexiWidget, whether via a snippet or a descendant component, has access to the `widget` controller through the same mechanism.

## Styling by state

The class-prop excerpts below extend the opening example. Keep its imports and enclosing board and target.

Whichever approach you use, the widget's own element is styled with its class prop (`class`), or with `widgetDefaults.className` further up the cascade. It accepts either a class value or a function that receives the widget's controller. Use a class function to style a widget while it is grabbed, previewed, or rejected:

- `isGrabbed` while the widget is being dragged, and `isResizing` while it is being resized.
- `isShadow` on the preview left in the grid while the widget is held.
- `dropRejected` while the widget is over a target that cannot place it. The shadow is withdrawn, the cursor becomes `not-allowed`, and releasing sends the widget back. The same flag is available on the target as `target.dropRejected`.

```svelte
<FlexiWidget
	class={(widget) => [
		'bg-muted rounded-lg px-4 py-2',
		widget.isShadow && 'opacity-50',
		widget.isGrabbed && 'animate-pulse opacity-50',
		widget.dropRejected && 'opacity-30'
	]}
>
	I'm a FlexiWidget!
</FlexiWidget>
```
