JSON config guide
createWorkflowFromConfig turns a plain JSON configuration into the same WorkflowDefinition produced by the JavaScript builder. Tours can therefore be authored in a CMS, stored in a database, or served by an API without changing how GlowTour renders or runs them.
The config API ships as a separate entry point, so applications using only the builder do not pay for it.
Quick start
Section titled “Quick start”Import the config entry point for your framework, load a JSON object, then run the generated workflow:
import { createGlowTour } from "@glowhop/react-tour";import { createWorkflowFromConfig } from "@glowhop/react-tour/config";
const config = await fetch("/tours/onboarding.json").then((response) => response.json());const workflow = createWorkflowFromConfig(config);
await createGlowTour().run(workflow);createWorkflowFromConfig accepts unknown, validates the complete configuration, and throws a ConfigValidationError before building when anything is invalid.
Configuration format
Section titled “Configuration format”{ "name": "onboarding", "cancellable": true, "overlay": { "opacity": 0.55 }, "popover": { "gap": 16 }, "steps": [ { "id": "invite-button", "target": "#invite-button", "title": "Invite your team", "content": "Send an invite to get started.", "data": { "trackingId": "invite-step" }, "actions": [ { "type": "waitUntilElement", "selector": "#invite-button", "timeout": 5000 }, { "type": "clickTarget" } ], "eventHandlers": [ { "event": "click", "action": { "type": "focusTarget" } } ] }, { "id": "done-banner", "target": "#done-banner", "title": "All set!", "content": "You're ready to go.", "actions": [{ "type": "wait", "ms": 400 }] } ]}nameandstepsare required.- Every step requires
id,target,title, andcontent. Step ids must be unique within the workflow; they are whatrun(workflow, { startAt })uses to resume a tour. targetis a CSS selector. Function andHTMLElementtargets remain builder-only.titleandcontentare strings for JSON loaded from a CMS or API.overlay,popover,indicator, andbehavioruse the same options as the builder, globally or per step.dataacceptsstring,number,boolean, andnullvalues.
Unknown keys, invalid nested options, and unsupported values are rejected rather than silently ignored.
Authoring JSON with TypeScript
Section titled “Authoring JSON with TypeScript”Use WorkflowConfig while authoring a JSON payload to get autocomplete and catch structural errors in the editor:
import type { WorkflowConfig } from "@glowhop/react-tour/config";
const config: WorkflowConfig = { name: "onboarding", steps: [ { target: "#invite-button", title: "Invite your team", content: "Send an invite to get started.", actions: [ { type: "waitUntilElement", selector: "#invite-button" }, { type: "clickTarget" }, ], }, ],};
const json = JSON.stringify(config, null, 2);Keep this object declarative when it must be transported as JSON. WorkflowConfig also accepts same-runtime JavaScript callbacks, but functions are not preserved by JSON.stringify.
Built-in actions
Section titled “Built-in actions”actions[] and eventHandlers[].action accept declarative action objects:
type |
Fields | Builder equivalent |
|---|---|---|
"wait" |
ms: number |
.wait(ms) |
"waitUntilElement" |
selector: string, interval?: number, timeout?: number |
.waitUntilElement(...) |
"clickTarget" |
- | .clickTarget() |
"focusTarget" |
- | .focusTarget() |
.waitUntil(predicate) has no JSON equivalent because an arbitrary predicate cannot be serialized. Use waitUntilElement or the JavaScript builder instead.
Validation errors
Section titled “Validation errors”All problems are reported together with their path:
import { ConfigValidationError } from "@glowhop/react-tour/config";
try { createWorkflowFromConfig(config);} catch (error) { if (error instanceof ConfigValidationError) { for (const issue of error.issues) { console.error(`${issue.path}: ${issue.message}`); } }}This makes CMS payloads and generated configuration easier to diagnose in one pass.
Adding JavaScript behavior
Section titled “Adding JavaScript behavior”Plain JSON covers targets, presentation options, data, and built-in actions. Same-runtime configuration objects can additionally contain functions, but they can no longer be transported as JSON.
actions[] and eventHandlers[].action accept an inline function:
import type { WorkflowConfig } from "@glowhop/react-tour/config";
const config: WorkflowConfig = { name: "onboarding", steps: [ { target: "#invite-button", title: "Invite your team", content: "Send an invite to get started.", actions: [ { type: "waitUntilElement", selector: "#invite-button" }, async (context) => { await analytics.track("invite_step_shown", { target: context.target.id }); }, ], }, ],};
const workflow = createWorkflowFromConfig(config);advanceAction, previousAction, and cancelAction, plus onStart, onCancel, and onFinish, accept only functions. Built-in actions cannot run in those contexts.
For CMS-driven behavior, keep an identifier in data and attach the implementation in application code:
const config = { ...parsed, steps: parsed.steps.map((step) => ({ ...step, advanceAction: (context: BeforeActionStepContext<string>) => { analytics.track(String(context.data?.trackingId ?? "unknown-step")); }, })),};Entry points
Section titled “Entry points”Framework adapters expose pre-bound config entry points:
@glowhop/react-tour/config@glowhop/vue-tour/config@glowhop/solid-tour/config@glowhop/angular-tour/config@glowhop/vanilla-tour/config
For direct core usage, import from @glowhop/core-tour/config:
import { createGlowTour } from "@glowhop/core-tour";import { createWorkflowFromConfig } from "@glowhop/core-tour/config";
const workflow = createWorkflowFromConfig(config);await createGlowTour<string>().run(workflow);Each entry point also exports the config types, ConfigValidationError, and validateWorkflowConfig.
Rich framework content
Section titled “Rich framework content”The default validation requires string values because that is the safe format for JSON from a CMS or API. For a configuration object assembled inside the application, framework content such as a React node, Vue VNode, Angular TemplateRef, or DOM Node can be accepted with the optional validateContent callback:
const workflow = createWorkflowFromConfig( { name: "onboarding", steps: [ { target: "#invite-button", title: <b>Invite your team</b>, content: "Send an invite to get started.", }, ], }, { validateContent: (value) => (value === undefined ? "must not be undefined" : null), },);validateContent(value, path) returns an error message or null. Keep the default string validation for untrusted JSON.
Security
Section titled “Security”The config module never evaluates strings as code: it uses no eval, new Function, or id-to-function registry. A payload produced by JSON.parse() cannot introduce executable functions.
Limitations
Section titled “Limitations”- CSS selector targets only.
- No declarative conditions such as
showIf. - No config exporter yet; the generated definition retains its validated source in
.source. - No built-in i18n integration. Translation keys and interpolation values can be stored in
contentanddata.
For the JavaScript builder equivalent, see the Builder reference and Programmatic control guide.
