w6w docs

Modals

Two general dialogs, Modal and ConfirmModal, and two complete flows built on them: AddConnectionModal and StepBuilderModal. The two flows call your server through W6WUIProvider.

Every modal here is a native <dialog>, so focus stays inside it and Esc closes it. Render a modal when you want it open and stop rendering it to close it. There’s no open prop.

A titled dialog for your own content. Esc and a click outside it both call onClose.

PropTypeDefaultWhat it does
titleReactNodeRequiredTitle row. A string also names the dialog for screen readers.
onClose() => voidRequiredEsc, outside click.
childrenReactNodeRequiredThe body.
size"default" | "wide" | "xl" | "full" | "fullscreen""default"wide fits a sidebar and content, xl a large work surface, full most of the viewport, fullscreen the whole viewport.
ariaLabelstringtitleAccessible name, when title isn’t a plain string.
titleIconReactNodeNoneNext to the title, such as an AppIcon.
subtitleReactNodeNoneMuted text after the title.
headerRightReactNodeNoneFar right of the title row, such as a back or close button.

A fullscreen modal has no backdrop to click, so put a visible close control in headerRight.

import { AppIcon, Modal } from "@w6w/ui";

{open && (
  <Modal
    title="Slack"
    titleIcon={<AppIcon name="Slack" size={20} />}
    subtitle="slack · v1.4.0"
    size="wide"
    onClose={() => setOpen(false)}
  >
    <AppDetails appId="slack" />
  </Modal>
)}

ConfirmModal

A yes/no dialog for a dangerous action, instead of the browser’s confirm().

PropTypeDefaultWhat it does
title, messagestringRequiredThe question and its consequence.
onConfirm() => voidRequiredThe confirm button. It doesn’t close the dialog: clear your pending state there too.
onClose() => voidRequiredCancel, Esc or outside click.
confirmLabel, cancelLabelstring"Confirm", "Cancel"Button text.
destructivebooleantrueDanger-styles the confirm button.
childrenReactNodeNoneExtra lines under the message, such as a warning.

Render it next to another open modal, not inside its body.

import { ConfirmModal } from "@w6w/ui";

{pendingDelete && (
  <ConfirmModal
    title="Delete workflow?"
    message={`"${pendingDelete.name}" and its run history will be removed.`}
    confirmLabel="Delete"
    onConfirm={() => {
      deleteWorkflow(pendingDelete.id);
      setPendingDelete(null);
    }}
    onClose={() => setPendingDelete(null)}
  />
)}

There’s another delete example on Buttons and icons.

AddConnectionModal (provider)

The full connect-an-app flow: pick an app, pick its auth method, then fill in the credential fields or complete OAuth in a popup.

PropTypeWhat it does
onClose() => voidRequired.
onCreated({ connectionId }) => voidRequired. Fired once the connection exists. Close the modal and refresh your list here.
initialAppIdstringSkip the picker and open on this app.
theme"light" | "dark"

It reads everything else from your client: listAppsPage (or listApps), getAppAuth, createConnection and startAppOAuthFlow. The picker shows category chips.

import { AddConnectionModal } from "@w6w/ui";

{adding && (
  <AddConnectionModal
    onClose={() => setAdding(false)}
    onCreated={({ connectionId }) => {
      setAdding(false);
      refreshConnections(connectionId);
    }}
  />
)}

For OAuth apps, allow popups from your site: the flow opens the vendor’s consent page in one, and fails with a message if the browser blocks it.

StepBuilderModal (provider)

Build one workflow step. The author picks what the step calls (a connected app’s action, a Function, a Workflow, or a built-in node such as a trigger, an if or a foreach), chooses a connection, fills in the parameters, sets retry and error handling, and tests it. It’s what WorkflowFlowEditor opens to add a step, and you can open it anywhere you need a step or a target.

PropTypeWhat it does
onClose() => voidRequired.
onAdd(step: BuiltStep) => string | voidRequired. Fired when the step is first complete. Return the id you gave it to receive later edits through onDraftChange.
onDraftChange(id, step) => voidEvery edit after onAdd. Without it, the builder adds the step once, when the author finishes.
titlestringHeading. Defaults to "Add a step".
appsOnlybooleanHide the workflow-only tabs (Triggers, Controls, Utilities, Data). For pickers that choose a target rather than add a canvas node.
callables("function" | "workflow")[]Which of the Functions and Workflows tabs to show. Defaults to both.
initialTab"connected" | "functions" | "workflows"The tab that opens first. Defaults to "connected".
appsFilter(app) => booleanLimit which apps can be picked.
initialApp, initialAction, initialConnection, initialWithOpen on an existing step’s settings, for editing.
connectionOnlybooleanStop once a connection is chosen, with no action or test. Pair it with onConnected(connectionId, app).
workflowId, stepIdstringThe step’s place in a saved workflow, so a previously saved passing test counts.
upstreamSteps{ id, label? }[]Earlier steps, so steps.<id>.output references resolve in a test.
theme"light" | "dark"

With a workflowId, the Triggers tab also lists app triggers. A webhook trigger is added with one click. A poll trigger first asks “Check every … minutes” (default 5, or the trigger’s minIntervalMs if higher) and creates the subscription with that interval sent as intervalMs, in milliseconds. The host enforces its own minimum and the picker shows its refusal as-is.

BuiltStep is a step without its id: { uses: { app, action, connection? }, with?, retry?, onError?, notes? }.

import { StepBuilderModal, type BuiltStep } from "@w6w/ui";

{building && (
  <StepBuilderModal
    onClose={() => setBuilding(false)}
    onAdd={(step: BuiltStep) => {
      const id = `step_${workflow.steps.length + 1}`;
      setWorkflow({ ...workflow, steps: [...workflow.steps, { id, ...step }] });
      setBuilding(false);
    }}
  />
)}

By default, an app step can’t be added until a test of it passes. That gate is what isTestRequired(surface) reports: it’s true unless the app or node says testRequired: false. requiredParamsFilled(params, values) is the other check the builder runs: whether every visible required parameter has a value. Both are exported for your own forms.

Where to next

  • Forms: the pieces the builder is made of, for building your own.
  • Workflow canvas: where the builder usually opens from.