Skip to content

Noise

A fine static grain laid over a surface with CSS, still by default.

Motionv0.1.0experimentalWCAG 2.2 AAView spec

Optional, and kept apart.

Nothing here is included in a project unless you add it, and the plain component it builds on is unchanged. This effect is decoration: it is hidden from screen readers, stands still for visitors who prefer reduced motion, and can be paused. Use Still on a preview to see that version.

Fine grain

Still, with no animation

import { Noise } from "@rdloom/react";

export default function NoiseBasic() {
  return (
    <div className="flex w-full justify-center">
      <div className="relative flex h-96 w-full items-center justify-center overflow-hidden rounded-xl border border-[var(--rd-color-border-default)] bg-[var(--rd-color-surface-default)]">
        <Noise />
        <div className="relative text-center">
          <p className="text-4xl font-semibold tracking-tight text-[var(--rd-color-text-default)]">Fine grain</p>
          <p className="text-base text-[var(--rd-color-text-muted)]">Still, with no animation</p>
        </div>
      </div>
    </div>
  );
}

Installation

npx rdloom add noise

Copies the source into src/components/rdloom. Edit it freely: rdloom upgrade merges later versions into your changes.

It also adds rdloom-motion.css next to your tokens and imports it from the tokens file, once: no setup, and no inline styles. The plain components you already use are untouched.

Use another registry client
npx shadcn@latest add https://rdloom.vimalbhatt.com/r/noise.json

Works, but without upgrade tracking, and you import the motion CSS yourself.

Usage

import { Noise } from "@rdloom/react";

<div className="flex w-full justify-center">
  <div className="relative flex h-96 w-full items-center justify-center overflow-hidden rounded-xl border border-[var(--rd-color-border-default)] bg-[var(--rd-color-surface-default)]">
    <Noise />
    <div className="relative text-center">
      <p className="text-4xl font-semibold tracking-tight text-[var(--rd-color-text-default)]">Fine grain</p>
      <p className="text-base text-[var(--rd-color-text-muted)]">Still, with no animation</p>
    </div>
  </div>
</div>

Overlay

Heavier grain

Opacity 0.18 on a flat surface

import { Noise } from "@rdloom/react";

export default function NoiseOverlay() {
  return (
    <div className="flex w-full justify-center">
      <div className="relative flex h-96 w-full items-center justify-center overflow-hidden rounded-xl border border-[var(--rd-color-border-default)] bg-[var(--rd-color-surface-default)]">
        <Noise opacity={0.18} size={120} />
        <div className="relative text-center">
          <p className="text-4xl font-semibold tracking-tight text-[var(--rd-color-text-default)]">Heavier grain</p>
          <p className="text-base text-[var(--rd-color-text-muted)]">Opacity 0.18 on a flat surface</p>
        </div>
      </div>
    </div>
  );
}

Animated

Shifting grain

Moves about once a second

import { Noise } from "@rdloom/react";

export default function NoiseAnimated() {
  return (
    <div className="flex w-full justify-center">
      <div className="relative flex h-96 w-full items-center justify-center overflow-hidden rounded-xl border border-[var(--rd-color-border-default)] bg-[var(--rd-color-surface-default)]">
        <Noise animated />
        <div className="relative text-center">
          <p className="text-4xl font-semibold tracking-tight text-[var(--rd-color-text-default)]">Shifting grain</p>
          <p className="text-base text-[var(--rd-color-text-muted)]">Moves about once a second</p>
        </div>
      </div>
    </div>
  );
}

API Reference

Defined by the spec. Components also accept the props of the React Aria component they wrap.

PropTypeDefault
opacity

Strength of the grain, from 0 to 1.

number0.14
size

Size of one grain tile in pixels.

number160
animated

Shifts the grain slowly, about once a second. Off by default.

booleanfalse
isStill

Stops the shift. Moving content should be stoppable.

booleanfalse

Accessibility

Role presentation, WCAG 2.2 AA. Tested with axe and keyboard tests; screen reader checks are in the audit checklist.

Keyboard

Not interactive.

Screen readers announce

  • Ignored: it is not announced

What your code must do

  • Pure decoration: aria-hidden, never focusable, and pointer-events none so content on top stays usable
  • Still by default; the optional shift is about once a second, far below 3 changes a second
  • Drawn with CSS only, so it needs no JavaScript and is safe in server HTML
  • Stands still for visitors who ask for less motion (prefers-reduced-motion), with isStill, and inside an rdm-still container
  • Nothing flashes more than 3 times a second (WCAG 2.3.1) and moving content can be stopped (WCAG 2.2.2)
  • Hidden in forced-colors (high contrast) mode so it never fights system colours
  • Keep text on top at 4.5:1 against the effect: use a low-contrast colour

Guidelines

Use it when

  • Taking the flat look off a large gradient or surface
  • A subtle film-grain feel

Avoid it when

  • With a high opacity that dirties text
  • On top of photos or charts where precision matters

Don't

  • Opacity above about 0.2
  • Stacking grain over text that must be crisp