useBranch
useBranch hook: trigger conditional branching paths from step content based on user choices or application state
Hook for triggering branch actions defined in a step's onAction prop. Use this to build interactive steps where users make choices that determine the tour path.
Usage
import { useBranch } from '@tour-kit/core';
function RoleSelectStep() {
const { triggerAction, hasAction, availableActions } = useBranch();
return (
<div>
<h2>What's your role?</h2>
<button
onClick={() => triggerAction('developer')}
disabled={!hasAction('developer')}
>
I'm a Developer
</button>
<button
onClick={() => triggerAction('designer')}
disabled={!hasAction('designer')}
>
I'm a Designer
</button>
</div>
);
}The useBranch hook must be used within a TourProvider or TourKitProvider context.
Return Value
Prop
Type
Step Configuration
For useBranch to work, the current step must define onAction:
<TourStep
id="role-select"
target="#role-buttons"
title="Choose Your Role"
interactive // Required for clickable elements
onNext={null} // Hide Next button
onAction={{
developer: 'dev-intro',
designer: 'design-intro',
manager: 'manager-intro',
}}
/>triggerAction
Triggers a named action, navigating to the associated branch target.
const { triggerAction } = useBranch();
// Basic usage
await triggerAction('developer');
// With payload (passed to resolver functions)
await triggerAction('submit', { formData: values });With Resolver Functions
When onAction uses a resolver function, the payload is available in the context:
// Step configuration
<TourStep
id="dynamic-step"
onAction={{
submit: (ctx) => {
const data = ctx.actionPayload as { score: number };
return data.score > 80 ? 'advanced-track' : 'basic-track';
},
}}
/>
// Component usage
<button onClick={() => triggerAction('submit', { score: 95 })}>
Submit Score
</button>hasAction
Check if an action is available for the current step. Useful for conditional rendering or button states.
const { hasAction } = useBranch();
if (hasAction('admin')) {
return <button onClick={() => triggerAction('admin')}>Admin Panel</button>;
}availableActions
Array of all action IDs defined in the current step's onAction.
const { availableActions, triggerAction } = useBranch();
return (
<div>
{availableActions.map((action) => (
<button key={action} onClick={() => triggerAction(action)}>
{action}
</button>
))}
</div>
);previewAction
Preview where an action would navigate without actually triggering navigation. Useful for showing users what will happen before they commit.
const { previewAction, triggerAction } = useBranch();
const [preview, setPreview] = useState<string | null>(null);
async function handleHover(actionId: string) {
const target = await previewAction(actionId);
setPreview(typeof target === 'string' ? target : 'special navigation');
}
return (
<button
onMouseEnter={() => handleHover('developer')}
onMouseLeave={() => setPreview(null)}
onClick={() => triggerAction('developer')}
>
Developer Path
{preview && <span>ā {preview}</span>}
</button>
);Complete Example
Here's a full example showing role-based branching:
import { useBranch, useTour } from '@tour-kit/core';
function RoleButtons() {
const { triggerAction, hasAction, availableActions } = useBranch();
const { isActive, currentStep } = useTour('onboarding');
// Only show when on the role-select step
if (!isActive || currentStep?.id !== 'role-select') {
return null;
}
const roles = [
{ id: 'developer', label: 'Developer', color: 'blue' },
{ id: 'designer', label: 'Designer', color: 'purple' },
{ id: 'manager', label: 'Manager', color: 'green' },
];
return (
<div className="flex gap-4">
{roles.map(({ id, label, color }) => (
<button
key={id}
onClick={() => triggerAction(id)}
disabled={!hasAction(id)}
className={`px-4 py-2 bg-${color}-100 text-${color}-800 rounded`}
>
{label}
</button>
))}
</div>
);
}And the corresponding tour configuration:
<Tour id="onboarding">
<TourStep
id="welcome"
target="#header"
title="Welcome!"
/>
<TourStep
id="role-select"
target="#role-buttons"
title="Choose Your Role"
content="Select a role to see personalized content"
interactive
onNext={null}
onAction={{
developer: 'dev-intro',
designer: 'design-intro',
manager: 'manager-intro',
}}
/>
<TourStep
id="dev-intro"
target="#api-docs"
title="Developer Tools"
onNext="summary"
onPrev="role-select"
/>
<TourStep
id="design-intro"
target="#design-panel"
title="Design Studio"
onNext="summary"
onPrev="role-select"
/>
<TourStep
id="manager-intro"
target="#dashboard"
title="Analytics Dashboard"
onNext="summary"
onPrev="role-select"
/>
<TourStep
id="summary"
target="#header"
title="All Set!"
onNext="complete"
/>
</Tour>Important Notes
Always set interactive={true} on steps where users need to click page elements. Without it, the overlay blocks all clicks.
Set onNext={null} to hide the Next button when you want users to make a choice via onAction instead of proceeding linearly.