Widgets

One shared surface for structured content, inside a conversation or anywhere in your product.

Use the same frame for your own features and third-party integrations. Use React content when your application renders the interface, or WidgetEmbed when the provider supplies an embedded page. The shared frame gives both a consistent title, source, and supporting context.

Launch checklist
Project workspace
0 of 3

Compose local features from the same library controls used throughout your product. This checklist places Vlak checkboxes inside Widget and records changes in this example.

Design review
Calendar · Example integration
30 min
When
Thursday, 10:00–10:30
With
Design team

Identify the provider and render its records with DescriptionList, forms, or other library components. A subtle Toggle makes the selected time visible below the content. The adapter owns authentication, fetching, and external actions; this example uses supplied calendar data without connecting an account.

Available times
Calendar · Embedded example

Use WidgetEmbed for a provider's embeddable page. This example is a separate local document with native time controls. It uses an empty sandbox because it needs no scripts or permissions.

import { Widget, WidgetEmbed } from "@noorddev/vlak-react";

<Widget title="Available times" provider="Calendar">
  <WidgetEmbed title="Choose a meeting time"
    src={providerEmbedUrl} height={320} />
</Widget>

The embed defaults to lazy loading, no referrer, and a sandbox that permits scripts and forms. Your application chooses the provider URL and any additional permissions. Give each frame a descriptive title and an explicit height; the surrounding widget stays fluid.

Cross-origin content owns its internal styles and focus order. Apply provider theme options where available. Vlak styles the outer frame and surrounding controls; it does not resize a remote document automatically or exchange messages with it.

  • Header. A clear title, provider attribution, and optional short metadata.
  • Content. React children for records, forms, lists, charts, or third-party components. Use Vlak tokens and controls to keep the presentation consistent.
  • Actions. Explicit controls below the content. Use Button with variant="subtle" for supporting actions, and confirm consequential changes with Confirmation.
  • Footer. Source context, update time, or the result of an action.

Every widget supports ready, loading, empty, and error states. The frame stays in place while the content changes. Retry waits for your callback and keeps failures readable. A successful request becomes ready only when your application supplies that state.

The interactive widget example uses a ButtonGroup with subtle buttons to explore those states, with one selected state at a time. Its controls form two columns on phones and keep 44px targets.

Keep the widget fluid within its container. Use 1px borders, subtle 4px corners, the existing typography, and 44px interactive targets. Name each control and preserve focus when data updates.

import { Widget, Toggle } from "@noorddev/vlak-react";

<Widget
  title={record.title}
  provider={integration.name}
  status={status}
  errorMessage="The provider could not load this record."
  onRetry={reload}
  actions={<Toggle variant="subtle" pressed={selected}
    onPressedChange={setSelected}>Select this time</Toggle>}
  footer={record.updatedLabel}
>
  <ProviderContent record={record} />
</Widget>

In this example, record, integration, status, reload, selected, setSelected, and ProviderContent come from your application. Pass a trusted React component through the content slot, and translate provider states into the widget states. Tokens are CSS custom properties, so provider components can use the same type, colors, spacing, and focus styles.

Widget accepts React content; WidgetEmbed hosts an application-selected iframe. Connection, authentication, and provider permissions belong to your application. See the Widget reference for props and interactive state examples, or read the AI integration guide for a complete conversation.