Motion & flows
A small animation engine (@pelagic-ui/core/motion) and React components built on it. Motion is always optional: with reduced motion everything snaps to its end state, decorative layers are hidden from assistive tech, anything that keeps moving has a pause button, and nothing flashes.
Try the RTL switch on each demo, and set your OS to reduce motion: every demo still works, without the movement.
13 components on this page. Every demo is live — change the theme in the header or flip a demo to right-to-left with its RTL button. These components are React-only for now; Vue, Svelte and Angular versions are coming.
Motion engine Link to Motion engine
animate(), spring(), timeline(), stagger(), drawPath(), tween(), animateLayout(), scrollProgress() and inView() — WAAPI with a requestAnimationFrame fallback.
Timeline: —
Code
ReactComing to Vue, Svelte and Angular.
import { animate, timeline, stagger, drawPath } from '@pelagic-ui/react'; // or '@pelagic-ui/core/motion'
timeline()
.add('.card', { opacity: [0, 1], y: [24, 0] }, { spring: { stiffness: 260, damping: 22 }, stagger: stagger(60) })
.add('.check path', { strokeDashoffset: [1, 0] }, { duration: 500 }, '-=200')
.play(); Motion & Presence Link to Motion & Presence
Declarative enter, update and exit animations; Presence keeps removed children mounted until their exit finishes.
- successChanges saved
Code
ReactComing to Vue, Svelte and Angular.
<Presence>
{toasts.map((t) => (
<Motion key={t.id} layout initial={{ opacity: 0, y: -12 }} animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.95 }} transition={{ spring: { stiffness: 320, damping: 28 } }}>
{t.text}
</Motion>
))}
</Presence> Reorder Link to Reorder
A sortable list: drag the handle with a mouse, pen or finger, or use the keyboard. Neighbours glide into place.
- 1.Audit with a screen readerA11y
- 2.Check the Arabic layoutRTL
- 3.Review dark mode contrastTheme
- 4.Publish release notesDocs
Order: A11y → RTL → Theme → Docs
Code
ReactComing to Vue, Svelte and Angular.
<Reorder label="Priorities" items={tasks} onReorder={setTasks}
getKey={(t) => t.id} getLabel={(t) => t.title}
renderItem={(t) => <span>{t.title}</span>} /> Stagger, Reveal & TextReveal Link to Stagger, Reveal & TextReveal
Reveal content as it scrolls into view: fades, blur-ins, staggered lists and word-by-word text.
Motion that respects people, in every language.
- Accessible
Revealed with a stagger.
- Themeable
Revealed with a stagger.
- Bilingual
Revealed with a stagger.
- Fast
Revealed with a stagger.
Code
ReactComing to Vue, Svelte and Angular.
<Stagger as="ul" each={80} effect="fade-up">
<li>Accessible</li><li>Themeable</li><li>Fast</li>
</Stagger>
<TextReveal as="h3" text="Motion that respects people" /> AnimatedTabs Link to AnimatedTabs
Tabs with a selection pill (or underline) that slides between tabs.
A sliding pill follows the selected tab.
$29 / month
Code
ReactComing to Vue, Svelte and Angular.
<AnimatedTabs label="Plan" tabs={[
{ value: 'monthly', label: 'Monthly', content: <Pricing period="month" /> },
{ value: 'yearly', label: 'Yearly', content: <Pricing period="year" /> },
]} /> Marquee Link to Marquee
An endless scrolling row or column — logos, testimonials, tickers.
Code
ReactComing to Vue, Svelte and Angular.
<Marquee label="Customers" speed={50}>
{logos.map((l) => <img key={l.name} src={l.src} alt={l.name} />)}
</Marquee> NumberTicker Link to NumberTicker
Counts up to a value when it scrolls into view; formatted with Intl.NumberFormat. Also exported as AnimatedCounter.
Code
ReactComing to Vue, Svelte and Angular.
<NumberTicker value={12840} locale="en-US" prefix="$" /> TypingText & MorphingText Link to TypingText & MorphingText
Typewriter text with a caret, and phrases that morph into each other.
Build dashboards, checkout flows, design systems
Pelagic is accessible, themeable, bilingual, fast
واجهات سهلة الوصول للجميع
Code
ReactComing to Vue, Svelte and Angular.
<h3>Build <TypingText words={['dashboards', 'forms', 'docs']} loop /></h3>
<MorphingText texts={['Accessible', 'Themeable', 'Bilingual']} /> SpotlightCard, AnimatedBorder & ShimmerButton Link to SpotlightCard, AnimatedBorder & ShimmerButton
Premium surfaces: a pointer-following spotlight, a light beam travelling the border, and a button with a soft sheen.
Pro plan
A light beam travels the border.
Team plan
Rotating gradient ring.
Code
ReactComing to Vue, Svelte and Angular.
<SpotlightCard>
<h3>Analytics</h3>
<p>Realtime dashboards.</p>
</SpotlightCard>
<AnimatedBorder>Pro plan</AnimatedBorder>
<ShimmerButton>Get started</ShimmerButton> Backgrounds Link to Backgrounds
AuroraBackground, GridPattern, DotPattern, Meteors, Particles and RippleRings for hero sections.
Hero
Ship accessible UI
Code
ReactComing to Vue, Svelte and Angular.
<AuroraBackground>
<GridPattern squares={[[2, 1], [5, 3]]} />
<h2>Ship accessible UI</h2>
</AuroraBackground> AnimatedList Link to AnimatedList
New items slide in, removed ones fade out, the rest glide into place.
- Workspace creatednow
Code
ReactComing to Vue, Svelte and Angular.
<AnimatedList label="Activity" items={events} getKey={(e) => e.id}
renderItem={(e) => <EventRow event={e} />} announce={(e) => `New: ${e.title}`} /> ScrollProgressBar & Parallax Link to ScrollProgressBar & Parallax
Reading progress for the page or a scroll container, and sections whose background drifts as you scroll.
Parallax
The background drifts as you scroll the page
Code
ReactComing to Vue, Svelte and Angular.
<ScrollProgressBar />
<Parallax background={<img src="/hero.jpg" alt="" />} speed={0.3}>
<h2>Chapter one</h2>
</Parallax> Wizard Link to Wizard
A multi-step flow with validation, optional steps, a review step, draft saving and a stepper that turns vertical in narrow containers.
Code
ReactComing to Vue, Svelte and Angular.
<Wizard label="Create workspace" persist="ws-draft" saveDraft steps={[
{ id: 'account', title: 'Account', content: (ctx) => <Input label="Email" {...wizardField(ctx, 'email')} />,
validate: ({ data }) => (data.email ? undefined : { email: 'Enter your email' }) },
{ id: 'plan', title: 'Plan', optional: true, content: <PlanPicker /> },
{ id: 'review', title: 'Review', review: true },
]} onComplete={save} />