# Neon sign

> A neon sign that hums and flickers on.

- Type: Component (light)
- Page: https://textlab.dev/components/neon-text
- Markdown: https://textlab.dev/components/neon-text.md
- Registry item: https://textlab.dev/r/neon-text.json
- Source file: `registry/textlab/neon-text/neon-text.tsx`
- Dependencies: none
- Variants: flicker, steady, pulse
- Keywords: neon, glow, flicker, sign, retro, synthwave

## When to use

- Nightlife, music and retro brands on dark backgrounds.
- A single sign-like word.

## When not to use

- Light backgrounds; the glow washes out.
- Running copy.

## Installation

### CLI

```bash
npx shadcn@latest add @textlab/neon-text
pnpm dlx shadcn@latest add @textlab/neon-text
```

The `@textlab` name needs `"registries": { "@textlab": "https://textlab.dev/r/{name}.json" }` in `components.json`. Without it, use the full URL:

```bash
npx shadcn@latest add https://textlab.dev/r/neon-text.json
```

Import the tokens once in your root layout: `import "@/components/textlab/tokens.css";`

### Manual

1. Install the dependencies: `npm install motion@12`
2. Copy `text-fx` (https://textlab.dev/r/text-fx.json) and this component into `components/textlab/`.

## Usage

```tsx
import { NeonText } from "@/components/textlab/neon-text/neon-text";

export function Example() {
  return <NeonText text="Open late" color="oklch(0.78 0.18 200)" />;
}
```

## API reference

### NeonText

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `text` (required) | `string` | – | The copy. |
| `variant` | `"flicker" \| "steady" \| "pulse"` | `"flicker"` | Powers on and stutters now and then, hums gently, or breathes its glow. |
| `color` | `string` | `hot pink` | Tube color. The core is mixed toward white. |
| `as` | `ElementType` | `"span"` | Rendered element. |
| `reducedMotion` | `"user" \| "always" \| "never"` | `"user"` | user follows the OS setting; always shows the still version. |
| `className` | `string` | – | Merged onto the root. |

## Accessibility

- Flicker stays under two flashes per second.
- The text is plain and unsplit.

## Motion

- Power-on takes 1.4 s, then a rare stutter every 7 s.
- Pulse breathes the halo over 3 s, not the letters.

## Reduced motion

The sign glows steadily with no flicker.

## Performance

- Text-shadow only; animation is CSS.
- Pulse animates text-shadow, which repaints; use it once per screen.

## Notes for AI

- Use only the props documented above. Do not invent props.
- Keep the screen-reader text and the reduced-motion branch when editing the source.
- Pick a variant from: flicker, steady, pulse.

## Related

- [Ember text](https://textlab.dev/components/ember-text.md): Letters land hot and cool down to the text color.
- [Aurora text](https://textlab.dev/components/aurora-text.md): Northern lights drift inside the letters.
- [Glitch text](https://textlab.dev/components/glitch-text.md): A controlled digital glitch on cue.

## Also in light

- [Gradient text](https://textlab.dev/components/gradient-text.md): Color flows slowly through the letters.
- [Shimmer text](https://textlab.dev/components/shimmer-text.md): A calm light passes across the words.
- [Holographic text](https://textlab.dev/components/holo-text.md): Foil that shifts color as you move across it.
- [Spotlight text](https://textlab.dev/components/spotlight-text.md): A light follows the cursor and reveals the copy.

## Source

### components/textlab/neon-text/neon-text.tsx

```tsx
"use client";

import type { CSSProperties, ElementType } from "react";
import { useReduced, type ReducedMotion } from "../lib/use-reduced";

export type NeonTextVariant = "steady" | "flicker" | "pulse";

export interface NeonTextProps {
  text: string;
  /** steady hums gently, flicker powers on and stutters now and then, pulse breathes its glow. */
  variant?: NeonTextVariant;
  /** Tube color. */
  color?: string;
  as?: ElementType;
  reducedMotion?: ReducedMotion;
  className?: string;
  style?: CSSProperties;
}

// Flicker never exceeds two flashes per second, well under the three-per-second seizure threshold.
const CSS = `
@keyframes tl-neon-on { 0% { opacity: 0.1; } 6% { opacity: 1; } 9% { opacity: 0.25; } 14% { opacity: 1; } 18% { opacity: 0.5; } 22%, 100% { opacity: 1; } }
@keyframes tl-neon-stutter { 0%, 91%, 93.5%, 100% { opacity: 1; } 92% { opacity: 0.45; } 96% { opacity: 0.85; } }
@keyframes tl-neon-hum { 0%, 100% { opacity: 1; } 50% { opacity: 0.93; } }
@keyframes tl-neon-pulse { 0%, 100% { text-shadow: var(--tl-neon-dim); } 50% { text-shadow: var(--tl-neon-full); } }
.tl-neon { color: color-mix(in oklab, var(--tl-neon) 30%, white); text-shadow: var(--tl-neon-full); }
.tl-neon[data-variant="steady"] { animation: tl-neon-hum 3.2s ease-in-out infinite; }
.tl-neon[data-variant="flicker"] { animation: tl-neon-on 1.4s steps(1) 1, tl-neon-stutter 7s steps(1) 1.4s infinite; }
.tl-neon[data-variant="pulse"] { animation: tl-neon-pulse 3s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) { .tl-neon[data-motion="user"] { animation: none !important; } }
`;

/** A neon sign that hums and flickers on. Layered glows give the tube a hot core and a soft halo. */
export function NeonText({ text, variant = "flicker", color = "oklch(0.72 0.24 350)", as: Tag = "span", reducedMotion = "user", className, style }: NeonTextProps) {
  const reduced = useReduced(reducedMotion);
  const glow = (k: number) =>
    `0 0 ${0.02 * k}em #fff, 0 0 ${0.08 * k}em var(--tl-neon), 0 0 ${0.18 * k}em var(--tl-neon), 0 0 ${0.42 * k}em color-mix(in oklab, var(--tl-neon) 70%, transparent), 0 0 ${0.9 * k}em color-mix(in oklab, var(--tl-neon) 45%, transparent)`;
  return (
    <Tag
      className={["tl-neon", className].filter(Boolean).join(" ")}
      data-variant={variant}
      data-motion={reducedMotion === "user" ? "user" : undefined}
      style={{ "--tl-neon": color, "--tl-neon-full": glow(1), "--tl-neon-dim": glow(0.55), ...(reduced ? { animation: "none" } : null), ...style } as CSSProperties}
    >
      <style href="tl-neon-text" precedence="default">{CSS}</style>
      {text}
    </Tag>
  );
}

export default NeonText;
```

Full library index: https://textlab.dev/llms.txt
