Widget

A surface with a subtle 1px outline and 4px corners for React content and provider iframes, with attribution, data states, actions, and supporting context.

Project brief
Workspace
One owner, one next step, and three supporting sources.

Workspace and connected results

Workspace data, a connected result, and an embedded page share the same widget structure. These examples use recorded results; no service is connected.

Launch checklist
This workspace
Owner
Mina
Next step
Review the final brief
Recent project files
Acme Drive · example provider
Project brief
Ready for review
Research notes
Three supporting sources
Available times
Calendar · Embedded example

Use it for

  • Present application data and third-party results with the same title, provider, content, action, and footer slots.
  • Map your integration's result to ready, loading, empty, or error. Supply rendered React content in children for the ready state.
  • Use WidgetEmbed in children for a provider iframe. Supply its embed address, a descriptive title, and an explicit height; the default height is 320px.
  • WidgetEmbed fills the available width and defaults to lazy loading, no-referrer, and a sandbox allowing scripts and forms. Set sandbox and allow for the provider's application-approved permissions.
  • Show the source in provider and an update time or other context in footer.
  • Use subtle Button actions and subtle ToggleGroup controls for supporting actions and visible view choices within a widget.
  • Use onRetry for an application-owned reload. Update status when data arrives; the widget does not fetch data or infer success.
  • CSS-only markup supplies the frame; data transitions and retry handling require React or application code.

Avoid

  • Treating this surface as a connector, authentication flow, or tool execution engine.
  • Passing untrusted markup or model-selected component names directly into rendered content.
  • Assuming the parent stylesheet can style a cross-origin iframe's interior. Provider theming, messaging, and automatic height coordination belong to the application integration.
  • Hiding consequential actions inside a widget without the application's normal confirmation step.

React package

npm install @noorddev/vlak-react

Load the stylesheet once at your app root, then import the components you use.

import "@noorddev/vlak-react/css";
import { Button, Widget, WidgetEmbed, type WidgetStatus } from "@noorddev/vlak-react";

Per-component imports are available at @noorddev/vlak-react/components/widget.

Copy the source

npx @noorddev/vlak-cli add widget

Adds the component and its dependencies to components/vlak/. Follow the StyleX setup to compile the source in your application.

shadcn registry

npx shadcn add https://vlak.dev/r/widget.json

Installs the same source through the shadcn CLI.

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

export function ConnectedWidgets({ status, onRetry, onOpenFiles, embedUrl }: {
  status: WidgetStatus;
  onRetry: () => void | Promise<void>;
  onOpenFiles: () => void;
  embedUrl: string;
}) {
  return <>
    <Widget title="Recent files" provider="Connected drive" status={status} onRetry={onRetry}
      emptyMessage="No files match this request." errorMessage="The drive could not be reached."
      actions={<Button variant="subtle" onClick={onOpenFiles}>Open files</Button>} footer="Updated just now">
      <p>Project brief · Ready for review</p>
    </Widget>
    <Widget title="Project board" provider="Connected board">
      <WidgetEmbed title="Project board from the connected provider" src={embedUrl} height={360} />
    </Widget>
  </>;
}

See the integration example to compose these components with your application's model and data.

Widget

A shared surface for application and third-party React content, with explicit data states.

PropTypeDefaultDescription
titlerequiredReactNodeVisible name of this widget and its region.
providerReactNodeName or linked attribution for the application or integration supplying the content.
iconReactNodeOptional decorative provider or content mark.
descriptionReactNode
statusWidgetStatus"ready"Application-supplied data state. The widget never fetches data itself.
statusLabelstring
emptyMessagestring"No results to show."
errorMessagestring"This widget could not be loaded."
onRetry() => void | Promise<void>
actionsReactNodeApplication-owned controls, rendered after the content.
footerReactNodeSupporting source, update time, or context below the actions.
childrenReactNode

Also accepts Omit<HTMLAttributes<HTMLElement>, "title">.

The ref reaches HTMLElement.

WidgetEmbed

An explicitly sized provider iframe for a Widget. Permissions and provider messaging remain application-owned.

PropTypeDefaultDescription
titlerequiredstringDescriptive name of the embedded interface, announced to assistive technology.
srcrequiredstringAddress supplied by the application or its connected provider.

Also accepts IframeHTMLAttributes<HTMLIFrameElement>.

The ref reaches HTMLIFrameElement.

KeysDoes
TabMoves through provider links, ready content, supplied actions, and the error state's retry button
Enter, SpaceActivates the focused retry button or supplied native button
Tab inside an embedFollows the provider document's native focus order; its keyboard interactions are supplied by that document
  • The section is named by its visible title unless an accessible name override is supplied.
  • Empty and loading messages use a status region; failures use an alert. Progress remains outside a busy region so it can be announced promptly.
  • A rejected retry remains readable and permits another attempt. Pending retries prevent duplicate activation, and changed data states invalidate stale retry results.
  • The decorative icon is hidden from assistive technology. Provider content and supplied actions remain in the normal reading and tab order.
  • WidgetEmbed requires a title that identifies the embedded document. The provider supplies the document's accessible content and keyboard behavior.
  • Native section attributes, className, style, and the section ref are forwarded. WidgetEmbed forwards native iframe attributes, permission overrides, and the iframe ref. The application supplies accessible content and controls for each integration.

The same styles are available as CSS. Native HTML provides the static presentation; React or application code supplies state updates and actions.

npm install @noorddev/vlak
import "@noorddev/vlak/css";
<section class="rs-widget" aria-labelledby="widget-title" data-status="ready"><header class="rs-widget-header"><div class="rs-widget-heading"><span class="rs-widget-title" id="widget-title">Recent files</span><div class="rs-widget-provider">Connected drive</div></div></header><div class="rs-widget-content"><p class="rs-widget-message">Project brief · Updated today</p></div><div class="rs-widget-footer">Supplied by the connected application</div></section>

Classes

.rs-widget.rs-widget-header.rs-widget-icon.rs-widget-heading.rs-widget-title.rs-widget-provider.rs-widget-label.rs-widget-content.rs-widget-description.rs-widget-state.rs-widget-message.rs-widget-actions.rs-widget-footer.rs-widget-embed