ai scroll horizontal snap cards features navigation ai scroll horizontal snap cards carousel dot-navigation intersection-observer horizontal scroll cards with dot navigation AI feature showcase with snap scrolling mobile-friendly feature cards carousel
Cards AI Scroll
Fetch pattern JSON:
curl https://webspire.de/patterns/cards/ai-scroll.json ai-scroll.html
<section class="ws-cards bg-[var(--ws-cards-bg)] py-20">
<div class="mx-auto max-w-7xl px-6">
<div class="mb-10 text-center">
<div class="mb-3 inline-flex items-center gap-2 rounded-full border border-[var(--ws-cards-border)] px-3 py-1 text-xs font-medium text-[var(--ws-cards-text-muted)]">
<svg class="h-3 w-3 text-[var(--ws-cards-accent)]" fill="currentColor" viewBox="0 0 16 16" aria-hidden="true"><path d="M8 1l1.5 3.5L13 6l-2.5 2.5.5 3.5L8 10.5 5 12l.5-3.5L3 6l3.5-.5z"/></svg>
AI Features
</div>
<h2 class="text-3xl font-bold tracking-tight text-[var(--ws-cards-text)] sm:text-4xl">Work smarter with AI</h2>
<p class="mt-4 text-lg text-[var(--ws-cards-text-soft)]">Your AI assistant is built right into your workflow — no switching tabs.</p>
</div>
<!-- Scroll container -->
<div
id="ai-scroll-track"
class="flex snap-x snap-mandatory gap-5 overflow-x-auto pb-4 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden"
role="list"
aria-label="AI feature cards"
>
<!-- Card 1: Write Smarter -->
<article
id="ai-card-0"
class="ws-ai-card flex w-[min(80vw,_320px)] shrink-0 snap-start flex-col rounded-2xl border border-[var(--ws-cards-border)] bg-[var(--ws-cards-bg)] p-6"
role="listitem"
>
<div class="mb-5 flex h-11 w-11 items-center justify-center rounded-xl bg-[var(--ws-cards-accent)]/10">
<svg class="h-5 w-5 text-[var(--ws-cards-accent)]" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931z"/>
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 7.125L18 8.625"/>
</svg>
</div>
<h3 class="mb-2 font-semibold text-[var(--ws-cards-text)]">Write Smarter</h3>
<p class="mb-5 text-sm text-[var(--ws-cards-text-soft)]">AI completes your sentences, suggests next paragraphs, and adapts to your writing style as you go.</p>
<!-- Preview element -->
<div class="mt-auto rounded-xl border border-[var(--ws-cards-border)] bg-[var(--ws-cards-text)]/[0.03] p-4">
<div class="mb-2 text-xs font-medium text-[var(--ws-cards-text-muted)]">Suggestion</div>
<p class="text-xs text-[var(--ws-cards-text-soft)] leading-relaxed">
"Our product helps teams ship faster by—
<span class="inline-block rounded bg-[var(--ws-cards-accent)]/15 px-1 text-[var(--ws-cards-accent)]">reducing context switching and centralizing work in one place."</span>
</p>
</div>
</article>
<!-- Card 2: Summarize -->
<article
id="ai-card-1"
class="ws-ai-card flex w-[min(80vw,_320px)] shrink-0 snap-start flex-col rounded-2xl border border-[var(--ws-cards-border)] bg-[var(--ws-cards-bg)] p-6"
role="listitem"
>
<div class="mb-5 flex h-11 w-11 items-center justify-center rounded-xl bg-[var(--ws-cards-accent)]/10">
<svg class="h-5 w-5 text-[var(--ws-cards-accent)]" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25H12"/>
</svg>
</div>
<h3 class="mb-2 font-semibold text-[var(--ws-cards-text)]">Summarize</h3>
<p class="mb-5 text-sm text-[var(--ws-cards-text-soft)]">Turn long documents into concise summaries. Get the key points in seconds, not hours.</p>
<!-- Preview element -->
<div class="mt-auto rounded-xl border border-[var(--ws-cards-border)] bg-[var(--ws-cards-text)]/[0.03] p-4 space-y-2">
<div class="mb-2 text-xs font-medium text-[var(--ws-cards-text-muted)]">TL;DR — 3 key points</div>
<div class="flex items-start gap-2">
<div class="mt-1 h-1.5 w-1.5 shrink-0 rounded-full bg-[var(--ws-cards-accent)]"></div>
<p class="text-xs text-[var(--ws-cards-text-soft)]">Q3 revenue up 24% YoY</p>
</div>
<div class="flex items-start gap-2">
<div class="mt-1 h-1.5 w-1.5 shrink-0 rounded-full bg-[var(--ws-cards-accent)]"></div>
<p class="text-xs text-[var(--ws-cards-text-soft)]">New enterprise tier launched</p>
</div>
<div class="flex items-start gap-2">
<div class="mt-1 h-1.5 w-1.5 shrink-0 rounded-full bg-[var(--ws-cards-accent)]"></div>
<p class="text-xs text-[var(--ws-cards-text-soft)]">Roadmap: API v2 in Q4</p>
</div>
</div>
</article>
<!-- Card 3: Translate -->
<article
id="ai-card-2"
class="ws-ai-card flex w-[min(80vw,_320px)] shrink-0 snap-start flex-col rounded-2xl border border-[var(--ws-cards-border)] bg-[var(--ws-cards-bg)] p-6"
role="listitem"
>
<div class="mb-5 flex h-11 w-11 items-center justify-center rounded-xl bg-[var(--ws-cards-accent)]/10">
<svg class="h-5 w-5 text-[var(--ws-cards-accent)]" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M10.5 21l5.25-11.25L21 21m-9-3h7.5M3 5.621a48.474 48.474 0 016-.371m0 0c1.12 0 2.233.038 3.334.114M9 5.25V3m3.334 2.364C11.176 10.658 7.69 15.08 3 17.502m9.334-12.138c.896.061 1.785.147 2.666.257m-4.589 8.495a18.023 18.023 0 01-3.827-5.802"/>
</svg>
</div>
<h3 class="mb-2 font-semibold text-[var(--ws-cards-text)]">Translate</h3>
<p class="mb-5 text-sm text-[var(--ws-cards-text-soft)]">Instantly translate your content into any language while preserving formatting and tone.</p>
<!-- Preview element -->
<div class="mt-auto rounded-xl border border-[var(--ws-cards-border)] bg-[var(--ws-cards-text)]/[0.03] p-4">
<div class="mb-3 flex items-center gap-2">
<span class="rounded bg-[var(--ws-cards-text)]/10 px-2 py-0.5 text-xs font-medium text-[var(--ws-cards-text-soft)]">EN</span>
<svg class="h-3 w-3 text-[var(--ws-cards-text-muted)]" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M13.5 4.5L21 12m0 0l-7.5 7.5M21 12H3"/></svg>
<span class="rounded bg-[var(--ws-cards-accent)]/15 px-2 py-0.5 text-xs font-medium text-[var(--ws-cards-accent)]">DE</span>
</div>
<p class="text-xs text-[var(--ws-cards-text-soft)]">"Ship faster" → <span class="text-[var(--ws-cards-text)]">"Schneller ausliefern"</span></p>
</div>
</article>
<!-- Card 4: Draw Ideas -->
<article
id="ai-card-3"
class="ws-ai-card flex w-[min(80vw,_320px)] shrink-0 snap-start flex-col rounded-2xl border border-[var(--ws-cards-border)] bg-[var(--ws-cards-bg)] p-6"
role="listitem"
>
<div class="mb-5 flex h-11 w-11 items-center justify-center rounded-xl bg-[var(--ws-cards-accent)]/10">
<svg class="h-5 w-5 text-[var(--ws-cards-accent)]" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M9.53 16.122a3 3 0 00-5.78 1.128 2.25 2.25 0 01-2.4 2.245 4.5 4.5 0 008.4-2.245c0-.399-.078-.78-.22-1.128zm0 0a15.998 15.998 0 003.388-1.62m-5.043-.025a15.994 15.994 0 011.622-3.395m3.42 3.42a15.995 15.995 0 004.764-4.648l3.876-5.814a1.151 1.151 0 00-1.597-1.597L14.146 6.32a15.996 15.996 0 00-4.649 4.763m3.42 3.42a6.776 6.776 0 00-3.42-3.42"/>
</svg>
</div>
<h3 class="mb-2 font-semibold text-[var(--ws-cards-text)]">Draw Ideas</h3>
<p class="mb-5 text-sm text-[var(--ws-cards-text-soft)]">Sketch rough shapes and let AI turn them into clean diagrams, flowcharts, and wireframes.</p>
<!-- Preview element -->
<div class="mt-auto rounded-xl border border-[var(--ws-cards-border)] bg-[var(--ws-cards-text)]/[0.03] p-4">
<div class="mb-2 text-xs font-medium text-[var(--ws-cards-text-muted)]">Sketch → Diagram</div>
<div class="flex items-center justify-center gap-3">
<div class="flex h-10 w-10 items-center justify-center rounded-lg border-2 border-dashed border-[var(--ws-cards-text-muted)]/40 text-[0.6rem] text-[var(--ws-cards-text-muted)]">box</div>
<svg class="h-3 w-3 text-[var(--ws-cards-accent)]" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M13.5 4.5L21 12m0 0l-7.5 7.5M21 12H3"/></svg>
<div class="flex h-10 w-16 items-center justify-center rounded-lg border border-[var(--ws-cards-accent)]/40 bg-[var(--ws-cards-accent)]/5 text-[0.6rem] font-medium text-[var(--ws-cards-accent)]">Component</div>
</div>
</div>
</article>
<!-- Card 5: Ask Anything -->
<article
id="ai-card-4"
class="ws-ai-card flex w-[min(80vw,_320px)] shrink-0 snap-start flex-col rounded-2xl border border-[var(--ws-cards-border)] bg-[var(--ws-cards-bg)] p-6"
role="listitem"
>
<div class="mb-5 flex h-11 w-11 items-center justify-center rounded-xl bg-[var(--ws-cards-accent)]/10">
<svg class="h-5 w-5 text-[var(--ws-cards-accent)]" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M8.625 12a.375.375 0 11-.75 0 .375.375 0 01.75 0zm0 0H8.25m4.125 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zm0 0H12m4.125 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zm0 0h-.375M21 12c0 4.556-4.03 8.25-9 8.25a9.764 9.764 0 01-2.555-.337A5.972 5.972 0 015.41 20.97a5.969 5.969 0 01-.474-.065 4.48 4.48 0 00.978-2.025c.09-.457-.133-.901-.467-1.226C3.93 16.178 3 14.189 3 12c0-4.556 4.03-8.25 9-8.25s9 3.694 9 8.25z"/>
</svg>
</div>
<h3 class="mb-2 font-semibold text-[var(--ws-cards-text)]">Ask Anything</h3>
<p class="mb-5 text-sm text-[var(--ws-cards-text-soft)]">Chat with your documents. Ask questions, find information, and get answers grounded in your content.</p>
<!-- Preview element -->
<div class="mt-auto space-y-2 rounded-xl border border-[var(--ws-cards-border)] bg-[var(--ws-cards-text)]/[0.03] p-4">
<div class="flex justify-end">
<div class="max-w-[80%] rounded-xl rounded-br-sm bg-[var(--ws-cards-accent)] px-3 py-2 text-xs text-white">
What's our Q3 goal?
</div>
</div>
<div class="flex justify-start">
<div class="max-w-[80%] rounded-xl rounded-bl-sm border border-[var(--ws-cards-border)] bg-[var(--ws-cards-bg)] px-3 py-2 text-xs text-[var(--ws-cards-text-soft)]">
Reach $2M ARR per your roadmap doc.
</div>
</div>
</div>
</article>
</div>
<!-- Dot navigation -->
<div class="mt-6 flex items-center justify-center gap-2" role="tablist" aria-label="AI feature card navigation">
<button
class="ws-ai-dot h-2 w-6 rounded-full bg-[var(--ws-cards-accent)] transition-all"
role="tab"
aria-selected="true"
aria-controls="ai-card-0"
aria-label="Card 1: Write Smarter"
data-index="0"
></button>
<button
class="ws-ai-dot h-2 w-2 rounded-full bg-[var(--ws-cards-text-muted)]/30 transition-all hover:bg-[var(--ws-cards-text-muted)]/60"
role="tab"
aria-selected="false"
aria-controls="ai-card-1"
aria-label="Card 2: Summarize"
data-index="1"
></button>
<button
class="ws-ai-dot h-2 w-2 rounded-full bg-[var(--ws-cards-text-muted)]/30 transition-all hover:bg-[var(--ws-cards-text-muted)]/60"
role="tab"
aria-selected="false"
aria-controls="ai-card-2"
aria-label="Card 3: Translate"
data-index="2"
></button>
<button
class="ws-ai-dot h-2 w-2 rounded-full bg-[var(--ws-cards-text-muted)]/30 transition-all hover:bg-[var(--ws-cards-text-muted)]/60"
role="tab"
aria-selected="false"
aria-controls="ai-card-3"
aria-label="Card 4: Draw Ideas"
data-index="3"
></button>
<button
class="ws-ai-dot h-2 w-2 rounded-full bg-[var(--ws-cards-text-muted)]/30 transition-all hover:bg-[var(--ws-cards-text-muted)]/60"
role="tab"
aria-selected="false"
aria-controls="ai-card-4"
aria-label="Card 5: Ask Anything"
data-index="4"
></button>
</div>
</div>
<script>
(function () {
const track = document.getElementById('ai-scroll-track');
const dots = document.querySelectorAll('.ws-ai-dot');
const cards = document.querySelectorAll('.ws-ai-card');
function setActiveDot(index) {
dots.forEach((dot, i) => {
const active = i === index;
dot.setAttribute('aria-selected', String(active));
dot.classList.toggle('w-6', active);
dot.classList.toggle('bg-[var(--ws-cards-accent)]', active);
dot.classList.toggle('w-2', !active);
dot.classList.toggle('bg-[var(--ws-cards-text-muted)]/30', !active);
});
}
// Intersection Observer: sync dots with visible card
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const index = Array.from(cards).indexOf(entry.target);
if (index !== -1) setActiveDot(index);
}
});
},
{ root: track, threshold: 0.6 }
);
cards.forEach((card) => observer.observe(card));
// Dot click: scroll to card
dots.forEach((dot) => {
dot.addEventListener('click', () => {
const index = Number(dot.dataset.index);
const card = cards[index];
if (card) {
card.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'start' });
}
});
});
})();
</script>
</section>
Details
Responsive Dark Mode SSR Safe Copy & Paste
Stable Published
aiscrollhorizontalsnapcardsfeaturesnavigation
Slots
| Name | Required | Description |
|---|---|---|
| heading | Yes | Section title, badge label, and subtitle above the scroll track. |
| cards | Yes | Five AI feature cards, each with icon, title, description, and a small preview element. |
| dots | Yes | Dot navigation buttons synchronized with the scroll position. |
Horizontal scrollbares Feature-Karussell mit fünf AI-Feature-Cards. Snap-Scrolling sorgt für sauberes Card-by-Card-Scrollen. Die Dot-Navigation unten synchronisiert sich per Intersection Observer automatisch mit der sichtbaren Card; ein Klick auf einen Dot scrollt direkt zur entsprechenden Card. Inspiriert von AFFiNE’s AI-Feature-Sektion.