Section
Product Workflow Section — Vercel
Dark monochrome numbered workflow section with a left step rail and a right sticky code/command preview that swaps per step. Three steps (ingest, route, resolve) with teal accent connectors, and a working step switcher that updates the preview panel live via a scoped script.
- Section
- Tailwind
- HTML
- MIT
Preview
Live section
9:41 100%
devsnips.dev/library/tailwind/sections/saas/product-workflow/vercel/ fluid · no fixed width 100%
Install
Add to your project
npx devsnips add Tailwind/Sections/SaaS/product-workflow/vercel Tailwind/Sections/SaaS/product-workflow/vercel <!--
Snippet Name: Product Workflow Section — Vercel
Description: Dark numbered workflow with a step rail and a live-swapping code/command preview panel.
Author: DevSnips Contributors
Usage Example: Drop into a "how it works" section. Click a step to swap the right-hand preview.
-->
<section class="relative w-full px-6 py-16 sm:py-24" data-workflow="vc">
<div class="mx-auto max-w-6xl">
<div class="mb-12 max-w-xl">
<p class="vc-mono mb-3 inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/[0.03] px-3 py-1 text-[11px] text-white/50"><span class="vc-dot"></span> How it works</p>
<h2 class="font-g text-[34px] font-semibold leading-[1.05] tracking-tight sm:text-[44px]">From event to resolution<br>in three moves.</h2>
</div>
<div class="grid grid-cols-1 gap-10 lg:grid-cols-[1fr_1fr]">
<!-- Step rail -->
<ol class="relative space-y-2" role="list">
<span class="absolute left-[18px] top-3 bottom-3 hidden w-px bg-white/10 sm:block" aria-hidden="true"></span>
<li>
<button type="button" data-step="1" aria-pressed="true"
class="workflow-step group relative flex w-full items-start gap-4 rounded-lg border border-white/10 bg-white/[0.02] p-5 text-left transition-colors hover:border-white/20 focus:outline-none focus-visible:ring-2 focus-visible:ring-white/30">
<span class="step-num font-g flex h-9 w-9 shrink-0 items-center justify-center rounded-full border border-white/15 bg-white/[0.04] text-[13px] font-semibold text-white/70 transition-colors">1</span>
<div class="min-w-0 flex-1">
<h3 class="font-g text-[17px] font-semibold text-white">Ingest from anywhere</h3>
<p class="font-g mt-1.5 text-[14px] leading-relaxed text-white/50">Stream events from your app, warehouse, or warehouse lake. We coerce schemas on the fly — no migration scripts.</p>
</div>
</button>
</li>
<li>
<button type="button" data-step="2" aria-pressed="false"
class="workflow-step group relative flex w-full items-start gap-4 rounded-lg border border-white/10 bg-white/[0.02] p-5 text-left transition-colors hover:border-white/20 focus:outline-none focus-visible:ring-2 focus-visible:ring-white/30">
<span class="step-num font-g flex h-9 w-9 shrink-0 items-center justify-center rounded-full border border-white/15 bg-white/[0.04] text-[13px] font-semibold text-white/70 transition-colors">2</span>
<div class="min-w-0 flex-1">
<h3 class="font-g text-[17px] font-semibold text-white">Route with rules + AI</h3>
<p class="font-g mt-1.5 text-[14px] leading-relaxed text-white/50">Combine deterministic rules and an intent model to assign, tag, and prioritize every event in milliseconds.</p>
</div>
</button>
</li>
<li>
<button type="button" data-step="3" aria-pressed="false"
class="workflow-step group relative flex w-full items-start gap-4 rounded-lg border border-white/10 bg-white/[0.02] p-5 text-left transition-colors hover:border-white/20 focus:outline-none focus-visible:ring-2 focus-visible:ring-white/30">
<span class="step-num font-g flex h-9 w-9 shrink-0 items-center justify-center rounded-full border border-white/15 bg-white/[0.04] text-[13px] font-semibold text-white/70 transition-colors">3</span>
<div class="min-w-0 flex-1">
<h3 class="font-g text-[17px] font-semibold text-white">Resolve & close the loop</h3>
<p class="font-g mt-1.5 text-[14px] leading-relaxed text-white/50">Auto-draft replies, escalate breaches, and write outcomes back to your source system — all audited.</p>
</div>
</button>
</li>
</ol>
<!-- Preview panel -->
<div class="lg:sticky lg:top-24 lg:self-start">
<div class="overflow-hidden rounded-[14px] border border-white/10 bg-[#0a0a0a] shadow-[0_0_0_1px_rgba(255,255,255,0.02),0_20px_60px_-20px_rgba(0,0,0,0.9)]">
<div class="flex items-center justify-between border-b border-white/[0.07] px-4 py-3">
<div class="flex items-center gap-2">
<span class="h-2.5 w-2.5 rounded-full bg-white/15"></span>
<span class="h-2.5 w-2.5 rounded-full bg-white/15"></span>
<span class="h-2.5 w-2.5 rounded-full bg-white/15"></span>
</div>
<span class="vc-mono text-[11px] text-white/40" data-preview-title>step 1 · ingest.ts</span>
<span class="vc-dot"></span>
</div>
<pre class="vc-mono overflow-x-auto p-5 text-[12.5px] leading-relaxed text-white/80"><code data-preview-body>// Stream product events to Flowbase
import { Flowbase } from "@flowbase/sdk";
const fb = new Flowbase(process.env.FB_KEY);
await fb.events.ingest({
source: "web-app",
name: "checkout.failed",
props: { plan: "scale", amount: 2400, region: "eu-west" },
});
// schema coerced automatically ✓
// backfill enabled by default ✓</code></pre>
</div>
<p class="vc-mono mt-3 text-[11px] text-white/35">preview updates as you select a step</p>
</div>
</div>
</div>
<script>
(function () {
const root = document.currentScript.closest('[data-workflow]');
const steps = root.querySelectorAll('[data-step]');
const title = root.querySelector('[data-preview-title]');
const body = root.querySelector('[data-preview-body]');
const previews = {
"1": { t: "step 1 · ingest.ts", c: `// Stream product events to Flowbase
import { Flowbase } from "@flowbase/sdk";
const fb = new Flowbase(process.env.FB_KEY);
await fb.events.ingest({
source: "web-app",
name: "checkout.failed",
props: { plan: "scale", amount: 2400, region: "eu-west" },
});
// schema coerced automatically ✓
// backfill enabled by default ✓` },
"2": { t: "step 2 · route.ts", c: `// Combine rules + intent model
import { Flowbase } from "@flowbase/sdk";
const fb = new Flowbase(process.env.FB_KEY);
await fb.routes.add({
when: { event: "checkout.failed", plan: "scale" },
then: [
{ tag: "billing", priority: "urgent" },
{ assign: "oncall-emea" },
{ draft: "ai-recovery" },
],
});
// intent model reruns every 6h ✓` },
"3": { t: "step 3 · resolve.ts", c: `// Resolve, reply, and close the loop
import { Flowbase } from "@flowbase/sdk";
const fb = new Flowbase(process.env.FB_KEY);
const r = await fb.tickets.resolve("A-128", {
reply: "ai-recovery",
status: "solved",
writeback: { source: "stripe", ref: "in_1AbC" },
});
console.log(r.auditUrl);
// fully audited ✓ SLA preserved ✓` }
};
function setStep(n) {
steps.forEach(s => {
const active = s.dataset.step === n;
s.setAttribute('aria-pressed', active ? 'true' : 'false');
s.classList.toggle('bg-white/[0.06]', active);
s.classList.toggle('border-white/20', active);
const num = s.querySelector('.step-num');
if (num) {
num.classList.toggle('bg-[#50e3c2]', active);
num.classList.toggle('text-black', active);
num.classList.toggle('border-[#50e3c2]', active);
}
});
const p = previews[n];
if (title) title.textContent = p.t;
if (body) body.textContent = p.c;
}
steps.forEach(s => s.addEventListener('click', () => setStep(s.dataset.step)));
setStep("1");
})();
</script>
</section> 155 lines UTF-8 · LF · Spaces: 2
Continue browsing