Digital Studio — Est. 2026

000%

( Free Tool )

← All tools

Snippet Library 

Battle-tested snippets for animations, accessibility patterns, and performance tricks — copied from production code we ship.

14 snippet(s)

tsx

GSAP reveal on scroll (context-safe)

Stagger content in using GSAP + ScrollTrigger inside a context so it reverts cleanly.

import { useEffect, useRef } from "react";
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
gsap.registerPlugin(ScrollTrigger);

export function Reveal({ children }: { children: React.ReactNode }) {
  const ref = useRef<HTMLDivElement>(null);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const ctx = gsap.context(() => {
      gsap.fromTo(el,
        { y: 48, autoAlpha: 0 },
        { y: 0, autoAlpha: 1, duration: 1, ease: "power3.out",
          scrollTrigger: { trigger: el, start: "top 88%", once: true } });
    }, el);
    return () => ctx.revert();
  }, []);
  return <div ref={ref}>{children}</div>;
}
GSAPScrollTrigger

ts

Lenis smooth scroll + GSAP ticker

Keep smooth scrolling in sync with GSAP's ScrollTrigger.

import Lenis from "lenis";
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";

gsap.registerPlugin(ScrollTrigger);
const lenis = new Lenis({ duration: 1.15, smoothWheel: true });
lenis.on("scroll", ScrollTrigger.update);
gsap.ticker.add((t) => lenis.raf(t * 1000));
gsap.ticker.lagSmoothing(0);
// call lenis.destroy() on unmount
LenisGSAP

ts

Respect prefers-reduced-motion

Gate heavy animation behind the user's motion preference.

const REDUCED =
  typeof window !== "undefined" &&
  window.matchMedia("(prefers-reduced-motion: reduce)").matches;

if (!REDUCED) {
  gsap.to(el, { x: 100, duration: 1 });
} else {
  gsap.set(el, { x: 0, autoAlpha: 1 }); // skip straight to final state
}
inclusivemotion

css

Accessible focus ring

Visible keyboard focus without ugly outlines on mouse clicks.

:focus-visible {
  outline: 2px solid #f97316;
  outline-offset: 3px;
  border-radius: 4px;
}
/* Hide only for mouse users — never remove :focus-visible */
:focus:not(:focus-visible) { outline: none; }
focusWCAG

tsx

Skip-to-content link

Let keyboard users jump straight to the main content.

export function SkipLink() {
  return (
    <a href="#main"
       className="sr-only focus:not-sr-only focus:absolute focus:top-4 focus:left-4
                  focus:z-50 focus:rounded focus:bg-white focus:px-4 focus:py-2">
      Skip to content
    </a>
  );
}
// <main id="main"> is the target
WCAGkeyboard

css

Visually-hidden (sr-only) utility

Hide text visually but keep it available to screen readers.

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0,0,0,0);
  white-space: nowrap;
  border: 0;
}
WCAGutility

html

Lazy-load images with width/height

Prevent CLS by reserving space and deferring offscreen loads.

<!-- Reserve layout space: never let CLS jump -->
<img
  src="hero.webp"
  width="1280"
  height="720"
  loading="lazy"
  decoding="async"
  alt="Describe the image"
/>
CLSLCP

css

Avoid FOIT with font-display

Show fallback text immediately, then swap when the webfont is ready.

@font-face {
  font-family: "Space Grotesk";
  src: url("/fonts/space-grotesk.woff2") format("woff2");
  font-display: swap;
  font-weight: 400 700;
}
fontsFOIT

html

Preload the LCP image

Hint the browser to fetch the largest element's image early.

<!-- In <head>: fetch the LCP image before CSS/JS parse -->
<link rel="preload" as="image" href="/hero.webp"
      imagesrcset="/hero-480.webp 480w, /hero-1280.webp 1280w"
      imagesizes="(max-width: 768px) 100vw, 1280px" />
LCP

css

Tight, scalable spacing grid

A consistent spacing scale as CSS custom properties.

:root {
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-6: 24px;
  --space-8: 32px;
  --space-12: 48px;
  --space-16: 64px;
}
.card { padding: var(--space-6); gap: var(--space-3); }
design systemtokens

css

Banding-free gradients with OKLCH

Perception-friendly color interpolation avoids muddy midpoints.

background: linear-gradient(
  135deg,
  oklch(0.7 0.15 40),
  oklch(0.55 0.2 280)
);
/* color(srgb ...) fallback for older browsers before it */
@supports not (background: oklch(0 0 0)) {
  .el { background: linear-gradient(135deg, #e0763f, #6a5bd0); }
}
colorgradient

css

Container queries

Make components respond to their container, not just the viewport.

.card-list { container-type: inline-size; }

.card { display: grid; gap: 1rem; }
@container (min-width: 480px) {
  .card { grid-template-columns: 200px 1fr; }
}
responsivecomponents

tsx

Stable callbacks with useCallback

Avoid re-render churn by memoizing handlers passed to children.

export function List() {
  const [items, setItems] = useState<string[]>([]);

  const addItem = useCallback((v: string) => {
    setItems((prev) => [...prev, v]);
  }, []);

  return (
    <ul>
      {items.map((it, i) => (
        <Row key={i} value={it} onRemove={removeItem(i)} />
      ))}
    </ul>
  );
}
hooksmemo

tsx

Lift shared state with Context

Share theme/auth state without prop drilling.

const ThemeCtx = createContext<{
  theme: "light" | "dark";
  toggle: () => void;
} | null>(null);

export function useTheme() {
  const ctx = useContext(ThemeCtx);
  if (!ctx) throw new Error("useTheme must be inside <ThemeProvider>");
  return ctx;
}

export function ThemeProvider({ children }: { children: React.ReactNode }) {
  const [theme, setTheme] = useState<"light"|"dark">("dark");
  const toggle = useCallback(() => setTheme(t => t === "dark" ? "light" : "dark"), []);
  return (
    <ThemeCtx.Provider value={{ theme, toggle }}>{children}</ThemeCtx.Provider>
  );
}
contextstate