# Particles

> Canvas particles drift gently, link up with fine lines and move out of the pointer's way; density scales with the area.

Particles background for React and shadcn: connected dots that react to the cursor

Page: https://goodui.dev/components/backgrounds/particles

## Install

```bash
npx shadcn@latest add @goodui/particles
```

Without the namespace: `npx shadcn@latest add https://goodui.dev/r/particles.json`. The file lands in `components/goodui/particles.tsx`.

## When to use

- Hero sections of AI, data or network products, where linked dots suggest connections.
- Login and sign-up screens that need gentle motion behind a centered form.
- Interactive landing sections where the background should move out of the cursor's way.

## When not to use

- A still texture: use dot-grid.
- Soft color without detail: use aurora, which is CSS-only.
- Behind dense app UI or long text: moving dots and lines compete with content. Use dot-grid with a fade.

## Pick by what matters

| Need | Use |
| --- | --- |
| Constellation with lines | defaults (connect, repel) |
| Floating dust, no lines | connect={false} density={2} |
| Background only, no pointer reaction | repel={false} |
| Brand colored | color="var(--primary)" |
| Lighter on low-end devices | density={0.8} maxParticles={120} or connect={false} |

## Usage

```tsx
import type { ReactNode } from "react"
import { Particles } from "@/components/goodui/particles"

export function LoginBackdrop({ children }: { children: ReactNode }) {
  return (
    <main className="relative grid min-h-svh place-items-center overflow-hidden bg-background">
      <Particles color="var(--primary)" density={1.2} />
      <div className="relative w-full max-w-sm rounded-2xl border bg-card p-6 shadow-sm">{children}</div>
    </main>
  )
}
```

### Dust only, no lines, no pointer reaction

```tsx
<Particles connect={false} repel={false} density={2} size={[0.5, 1.2]} speed={6} />
```

## API

### Particles

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| density | `number` | `1.4` | Particles per 10,000 px² of area. |
| maxParticles | `number` | `220` | Hard cap on the particle count. |
| size | `[number, number]` | `[0.6, 1.8]` | Radius range in px. |
| speed | `number` | `10` | Drift speed in px per second. |
| connect | `boolean` | `true` | Draw lines between nearby particles. |
| linkDistance | `number` | `110` | Max distance for a connecting line, in px. |
| repel | `boolean` | `true` | Push particles away from the pointer (listens on the parent element). |
| repelRadius | `number` | `110` | Distance in px within which the pointer pushes particles away. |

Also accepts every <div> attribute.

## Accessibility

- The canvas wrapper is aria-hidden and has pointer-events: none, so content above it stays clickable.
- Reduced motion shows one still frame.

## Motion

- Each particle drifts in its own direction at 40% to 100% of `speed` px per second (10) and wraps around the edges.
- With connect, particles closer than `linkDistance` px (110) are joined by thin lines that fade with distance.
- With repel, the pointer pushes particles within `repelRadius` px (110) away; they ease back to their own drift.
- It pauses while off-screen and while the tab is hidden. Reduced motion: one still frame is drawn.

## Performance

- Canvas 2D, devicePixelRatio capped at 2. The count is density per 10,000 px² of area, capped by maxParticles (220).
- Lines are checked between every pair of particles, so cost grows quickly with the count; lower density or turn off connect on large areas.
- The color is resolved once and re-read when the theme class on <html> or the system color scheme changes.

## Notes for AI

- Place it inside a relative parent; it fills it with absolute inset-0. Give the content after it position: relative.
- repel listens to pointer moves on the parent element, since the canvas itself ignores the pointer.
- size is a [min, max] radius tuple in px; speed is px per second.
- color accepts any CSS color or variable and is resolved for canvas automatically.

## FAQ

**Is this tsParticles or particles.js?**

No. It is a small hand-written Canvas 2D component with no dependencies.

**Does it follow dark mode?**

Yes. With the default var(--foreground), or any theme variable, it re-reads the color when the theme changes.

## Related

- dot-grid: https://goodui.dev/components/backgrounds/dot-grid
- flickering-grid: https://goodui.dev/components/backgrounds/flickering-grid
- aurora: https://goodui.dev/components/backgrounds/aurora
- spotlight-card: https://goodui.dev/components/cards/spotlight-card

Last updated: 2026-11-02
