v1.0
Guides / Page 02·05

Widget rendering

Learn about approaches to rendering widgets in Flexiboards.

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:

Svelte Styling by state
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.
Drag me
Fixed

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

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

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

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