
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
@rilaykit/workflow
Advanced tools
The multi-step workflow engine for RilayKit — build complex, production-ready wizard flows with navigation, persistence, analytics, and plugins.
@rilaykit/workflow extends @rilaykit/forms with a real workflow engine: step navigation with guards, auto-persistence to any storage backend, analytics tracking, cross-step conditions, and a plugin system for reusable behavior.
# pnpm (recommended)
pnpm add @rilaykit/core @rilaykit/forms @rilaykit/workflow
# npm
npm install @rilaykit/core @rilaykit/forms @rilaykit/workflow
# yarn
yarn add @rilaykit/core @rilaykit/forms @rilaykit/workflow
# bun
bun add @rilaykit/core @rilaykit/forms @rilaykit/workflow
@rilaykit/coreand@rilaykit/formsare required peer dependencies.
import { required, email, minLength } from '@rilaykit/core';
const accountForm = form.create(rilay, 'account')
.add({
id: 'email',
type: 'input',
props: { label: 'Email' },
validation: { validate: [required(), email()] },
})
.add({
id: 'password',
type: 'input',
props: { label: 'Password', type: 'password' },
validation: { validate: [required(), minLength(8)] },
});
const profileForm = form.create(rilay, 'profile')
.add(
{ id: 'firstName', type: 'input', props: { label: 'First Name' } },
{ id: 'lastName', type: 'input', props: { label: 'Last Name' } },
);
import { flow } from '@rilaykit/workflow';
import { LocalStorageAdapter } from '@rilaykit/workflow';
// Option 1: With explicit ID and name
const onboarding = flow
.create(rilay, 'onboarding', 'User Onboarding')
.step({
id: 'account',
title: 'Create Account',
formConfig: accountForm,
})
.step({
id: 'profile',
title: 'Your Profile',
formConfig: profileForm,
allowSkip: true,
})
.configure({
persistence: {
adapter: new LocalStorageAdapter({ maxAge: 7 * 24 * 60 * 60 * 1000 }),
options: { autoPersist: true, debounceMs: 500 },
},
analytics: {
onStepComplete: (stepId, duration) => {
trackEvent('step_complete', { stepId, duration });
},
onWorkflowComplete: (id, totalTime) => {
trackEvent('workflow_complete', { id, totalTime });
},
},
})
.build();
// Option 2: Auto-generated ID and default name
const quickWorkflow = flow
.create(rilay) // ID and name are optional
.step({ title: 'Step 1', formConfig: accountForm })
.build();
import {
Workflow,
WorkflowBody,
WorkflowStepper,
WorkflowNextButton,
WorkflowPreviousButton,
} from '@rilaykit/workflow';
function OnboardingFlow() {
const handleComplete = (data: Record<string, unknown>) => {
console.log('Workflow complete:', data);
};
return (
<Workflow workflowConfig={onboarding} onComplete={handleComplete}>
<WorkflowStepper />
<WorkflowBody />
<div>
<WorkflowPreviousButton />
<WorkflowNextButton />
</div>
</Workflow>
);
}
Chainable API for defining multi-step flows with step-level configuration.
import { flow } from '@rilaykit/workflow';
const checkoutFlow = flow
.create(rilay, 'checkout', 'Checkout Flow')
.step({ id: 'cart', title: 'Review Cart', formConfig: cartForm })
.step({ id: 'shipping', title: 'Shipping', formConfig: shippingForm })
.step({ id: 'payment', title: 'Payment', formConfig: paymentForm })
.configure({ persistence: { ... }, analytics: { ... } })
.use(myPlugin)
.build();
Navigation with validation guards — users can't advance until the current step validates. Steps can be optional with allowSkip: true.
.step({
id: 'profile',
title: 'Your Profile',
formConfig: profileForm,
allowSkip: true,
})
Use when('stepId.fieldId') to reference fields from other steps. Steps can be conditionally visible or skippable.
import { when } from '@rilaykit/core';
.step({
id: 'business-details',
title: 'Business Details',
formConfig: businessForm,
conditions: {
visible: when('account.accountType').equals('business'),
},
})
Use onAfterValidation to pre-populate fields in upcoming steps based on current step data.
.step({
id: 'account',
title: 'Account',
formConfig: accountForm,
onAfterValidation: (stepData, helper) => {
helper.setNextStepValue('profile', 'email', stepData.email);
},
})
Auto-save workflow state to any storage backend through an adapter interface. Ships with LocalStorageAdapter, and you can implement your own for Supabase, your API, or any backend.
import { LocalStorageAdapter } from '@rilaykit/workflow';
.configure({
persistence: {
adapter: new LocalStorageAdapter({
prefix: 'rilay-',
maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days
}),
options: {
autoPersist: true,
debounceMs: 500,
storageKey: 'onboarding-v1',
},
},
})
Custom adapter interface:
interface WorkflowPersistenceAdapter {
save(key: string, data: unknown): Promise<void>;
load(key: string): Promise<unknown | null>;
remove(key: string): Promise<void>;
exists(key: string): Promise<boolean>;
listKeys?(): Promise<string[]>;
clear?(): Promise<void>;
}
Track step completions, drop-offs, time per step, and errors with callback hooks.
.configure({
analytics: {
onStepComplete: (stepId, duration) => { ... },
onStepSkip: (stepId) => { ... },
onWorkflowComplete: (id, totalTime) => { ... },
onError: (stepId, error) => { ... },
},
})
Encapsulate reusable cross-cutting behavior with plugins. Plugins support dependency declaration.
const loggingPlugin = {
name: 'logging',
onStepEnter: (stepId) => console.log(`Entering ${stepId}`),
onStepLeave: (stepId) => console.log(`Leaving ${stepId}`),
};
const flow = rilay
.flow('checkout', 'Checkout')
.use(loggingPlugin);
| Component | Description |
|---|---|
<Workflow> | Main wrapper — manages context and state |
<WorkflowProvider> | Context provider (used separately when needed) |
<WorkflowBody> | Renders the current step's form |
<WorkflowStepper> | Progress indicator / step navigation |
<WorkflowNextButton> | Advance to next step (or submit on last step) |
<WorkflowPreviousButton> | Go back to previous step |
<WorkflowSkipButton> | Skip the current step |
| Hook | Description |
|---|---|
useWorkflowContext() | Full workflow context |
useWorkflowState() | Current workflow state |
useWorkflowNavigation() | Navigation actions (next, previous, goTo) |
useWorkflowConditions() | Evaluated step conditions |
useWorkflowSubmission() | Submission state and handlers |
useWorkflowAnalytics() | Analytics tracking |
useConditionEvaluation() | Condition evaluation utilities |
usePersistence() | Persistence state and actions |
useStepMetadata() | Current step metadata |
@rilaykit/core (registry, types, validation, conditions)
↑
@rilaykit/forms (form builder + React components)
↑
@rilaykit/workflow ← you are here
Full documentation at rilay.dev:
MIT — see LICENSE for details.
FAQs
Workflow and multi-step form utilities for RilayKit
The npm package @rilaykit/workflow receives a total of 111 weekly downloads. As such, @rilaykit/workflow popularity was classified as not popular.
We found that @rilaykit/workflow demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.