Aaditya

Dither Gradient

Backgrounds

About

A linear, radial or conic tonal ramp drawn as a 1 bit dither, the monochrome replacement for gradient fills. Sharp at any size and colored by your theme tokens.

Built with React and Tailwind. Copy the prompt and paste it into Claude Code, Cursor or Lovable: your agent adds Dither Gradient to your project and fits it to your theme.

Code

How Dither Gradient is used: the demo's code. The component's own source comes with a free account.

Usage.tsx

"use client"

import * as React from "react"
import { DitherGradient } from "@/components/ui/dither-gradient"

const FIT_CSS = "html,body{overflow:hidden}[data-fit-small] [data-fit-hide]{display:none!important}"

/**
 * 21st shows a demo in a small frame: about 674 by 421 on a component page, 358 by 224 on a
 * phone and 245 by 139 on a profile card. A demo taller than its frame gets scrollbars, which
 * render white on dark pages. FitFrame fills the frame exactly instead.
 *
 * - "scale": the content shrinks until it fits, centered. For visuals such as orbs.
 * - "crop": the content stays at full size from the top and fades out at the bottom. For text
 *   that streams in, where a changing scale would make the page breathe.
 *
 * Anything marked `data-fit-hide` (state buttons, the chatcn.dev line) drops out in frames
 * shorter than `hideBelow`, so a profile card shows the visual alone.
 */
function FitFrame({
  children,
  mode = "scale",
  hideBelow = 360,
}: {
  children: React.ReactNode
  mode?: "scale" | "crop"
  hideBelow?: number
}) {
  const content = React.useRef<HTMLDivElement>(null)
  const [cropped, setCropped] = React.useState(false)

  React.useLayoutEffect(() => {
    const el = content.current
    if (!el) return
    const measure = () => {
      const vw = window.innerWidth
      const vh = window.innerHeight
      el.toggleAttribute("data-fit-small", vh < hideBelow)
      // Layout sizes ignore the transform, so measuring never feeds back.
      const w = Math.max(el.offsetWidth, el.scrollWidth)
      const h = Math.max(el.offsetHeight, el.scrollHeight)
      const scale = mode === "scale" ? Math.min(1, vw / w, vh / h) : 1
      el.style.transform = scale < 1 ? `scale(${scale})` : ""
      setCropped(mode === "crop" && h > vh + 1)
    }
    measure()
    const observer = new ResizeObserver(measure)
    observer.observe(el)
    window.addEventListener("resize", measure)
    return () => {
      observer.disconnect()
      window.removeEventListener("resize", measure)
    }
  }, [mode, hideBelow])

  const fade = "linear-gradient(to bottom, #000 calc(100% - 40px), transparent)"
  return (
    <div
      className="flex w-full justify-center overflow-hidden"
      style={{
        height: "100dvh",
        alignItems: mode === "crop" ? "flex-start" : "center",
        maskImage: cropped ? fade : undefined,
        WebkitMaskImage: cropped ? fade : undefined,
      }}
    >
      <style>{FIT_CSS}</style>
      <div
        ref={content}
        className="w-full shrink-0"
        style={{ transformOrigin: mode === "crop" ? "top center" : "center" }}
      >
        {children}
      </div>
    </div>
  )
}

/**
 * A release banner lit by a dithered ramp instead of a color gradient. The copy sits on clear
 * paper and the ramp rises from the foot, so the type never competes with the dots.
 */
function DitherGradientDemo() {
  return (
    <div className="rounded-(--chatcn-radius-xl) bg-(color:--chatcn-bg) shadow-(--chatcn-shadow-border) flex w-full max-w-2xl flex-col items-center overflow-hidden text-center">
      <div className="flex flex-col items-center px-6 pt-12 pb-4 sm:pt-14">
        <p className="text-[0.8125rem]/[1.25rem] text-(color:--chatcn-fg-muted) font-medium">Version 0.4</p>
        <h2 className="text-[2rem]/[2.5rem] tracking-[-0.028em] text-(color:--chatcn-fg) mt-2 font-semibold text-balance">
          Effects that follow your theme
        </h2>
        <p className="text-[0.9375rem]/[1.5rem] tracking-[-0.006em] text-(color:--chatcn-fg-muted) mt-3 max-w-md text-pretty">
          Dither, halftone and ASCII, drawn from the same tokens as the rest of your interface.
        </p>
      </div>
      <DitherGradient
        aria-hidden="true"
        type="radial"
        center={[0.5, 1]}
        from={1}
        to={0}
        smooth
        pixelSize={1.5}
        className="h-36 w-full sm:h-44"
      />
    </div>
  )
}

/** The line under each 21st demo that points back to the kit. */
function MoreOn({ slug, children }: { slug: string; children: React.ReactNode }) {
  return (
    <p data-fit-hide className="text-[0.75rem]/[1rem] text-(color:--chatcn-fg-faint) text-center text-balance">
      {children}{" "}
      <a
        href={`https://chatcn.dev/docs/components/${slug}`}
        target="_blank"
        rel="noopener"
        className="text-(color:--chatcn-fg-subtle) hover:text-(color:--chatcn-fg) underline underline-offset-2"
      >
        chatcn.dev
      </a>
    </p>
  )
}

export default function DitherGradientPreview() {
  return (
    <FitFrame>
      <div className="flex w-full flex-col items-center justify-center gap-10 p-6">
        <DitherGradientDemo />
        <MoreOn slug="dither-gradient">
          Linear, radial and conic ramps that follow your theme. More on
        </MoreOn>
      </div>
    </FitFrame>
  )
}

More by Aaditya

View all
  • Dither Orb

    Dither Orb

    7
  • Pixel Orb

    Pixel Orb

    2
  • Voice Orb

    Voice Orb

    2
  • Wireframe Globe

    Wireframe Globe

    1
  • Particle Text

    Particle Text

    1
  • Split Flap

    Split Flap

    1
  • Agent Lanes

    Agent Lanes

    1
  • Audio Visualizer

    Audio Visualizer

    1

More in Backgrounds

View all
  • Elegant Dark Pattern

    Elegant Dark Pattern

    877
  • Background snippets

    Background snippets

    112
  • Gradient Backgrounds

    Gradient Backgrounds

    28
  • Tailwind CSS Background Snippet

    Tailwind CSS Background Snippet

    581
  • Background Components

    Background Components

    16
  • Jade Sky

    Jade Sky

    98
  • Light theme Tailwind CSS Background Snippet

    Light theme Tailwind CSS Background Snippet

    241
  • LivingOrigami bg

    LivingOrigami bg

    155

Explore more

Part of chatcn — browse the full library on 21st.dev.