shadcn.io is not affiliated with official shadcn/ui
Grain lays fine film grain over any surface: a speckle you feel more than see, re-rolled 24 times a second like grain in projected film. The noise is two small SVG tiles of different sizes, drawn once by the browser; keyframes the install adds to your stylesheet jump them to new offsets in steps, so no JavaScript runs and nothing repaints while it moves. The tiles' noise is tuned so it never beats against the pixel grid, so no woven pattern or tile grid shows, at 1× or on a retina screen. It takes your theme's foreground colour, so it's dark print grain on a light page and pale film grain on a dark one.
Put it over a flat colour or a gradient to take the digital flatness off a hero. For a texture that holds still, use Paper; for print dots rather than film grain, Halftone. It pairs with Mesh Gradient underneath, or with Spotlight for a cinematic glow. For signal noise that tears and shifts, use Glitch; for a quieter, static texture, Dot Pattern.
Installation
Usage
import { Grain } from "@/components/ui/grain";<Grain className="min-h-[480px]">
<h1>Every surface has a texture</h1>
</Grain>Grain is a container: your content goes inside it, and the grain sits behind that content and above the container's own background. Give it a size, a background colour or a gradient with className; for a whole page, className="fixed inset-0 -z-10" with no children.
Demos
Grainy Gradient
Put the gradient on the root with className, and the grain lands on top of it. intensity="strong" and grainColor="white" give the gritty look that suits a dark, saturated gradient.
Warm Film
grainColor takes any CSS colour: amber over dark brown reads as warm film stock. speed={0.5} halves the rate to 12 jumps a second, for a slower, drifting grain.
Accessibility
The grain is decoration: it's hidden from assistive tech and never takes the pointer, so everything you put inside works as usual. With reduced motion the grain holds still, as a texture, and in forced-colors mode it's hidden. Its overall brightness stays the same from one step to the next, so it doesn't flash; speed is capped at twice the default. At the default intensity the specks cover a few percent of the surface at low opacity, so text in your foreground colour keeps its contrast; use intensity="subtle" behind small body text over a busy gradient.
FAQ
How do I make the grain stronger or fainter?
Use intensity: subtle behind body text, medium (the default, felt rather than seen) for a hero, strong for a gritty dark section or a saturated gradient.
How do I get the grainy-gradient look?
Put the gradient on the root, such as className="bg-[radial-gradient(…)]". The grain sits above the root's background and under your content.
Can I change the grain's colour?
Pass any CSS colour to grainColor, such as amber over dark brown for warm film or white over a deep gradient. By default it's your theme's foreground colour, so it follows light and dark mode.
Why doesn't a grid or a repeat show?
Two things. The noise is drawn at a frequency that doesn't beat against the pixel grid (near one speck per pixel, noise turns into a woven grid), and the two tiles have prime sizes, 241 and 179 pixels, so their sum never repeats on screen.
How fast does it move, and can I change that?
24 jumps a second by default, the rate of projected film. speed multiplies it, from 0.25 (6 a second, a slow drift) to 2 (48 a second).
API Reference
Grain
<div> data-slot="grain"
grainColor?string
The speckle's colour: any CSS colour.
- Default
"var(--foreground)"
intensity?"subtle" | "medium" | "strong"
How strong the grain is: subtle behind body text, medium for a
hero, strong for a gritty dark section.
- Type
"subtle" | "medium" | "strong"- Default
"medium"
speed?number
How fast the grain re-rolls: a multiplier of 24 frames a second, from 0.25 to 2.
- Default
1
render?ReactElement | ((props: object, state: object) => ReactElement)
Replace the host element or compose it with another component.
- Type
ReactElement | ((props: object, state: object) => ReactElement)
className?string
Merged with the part's classes.
--grain-colorstring
The speckle's colour (var(--foreground)).
--grain-durationstring
One cycle of 12 steps (500ms): longer is slower.
Related
- Pro


Paper Background
TextureA still, warm texture instead of moving speckle
- Pro


Halftone Background
TexturePrint dots instead of film grain


Mesh Gradient Background
GradientsThe gradient to put under the grain
- Pro


Spotlight Background
LightA cinematic glow that pairs with grain
- Pro


Signal noise with motion


Dot Pattern
GridsA quieter static texture