Components
MDX lets you drop live React components straight into prose. Here's an interactive client component using the same neumorphic primitives as the rest of the theme — the buttons physically depress (inset shadow) on press.
Press the buttons
Buttons
Two variants, both theme-accent aware. The primary button is colored glass — the active theme's accent gradient (white text on light themes, black on dark). The secondary button is a neumorphic surface with accent-colored text. Switch themes in the navbar and watch both retint.
import { Button } from '../components/Button'
<Button variant="primary" href="/old/1.0/getting-started">Get started</Button>
<Button variant="secondary" onClick={...}>Learn more</Button>
Neumorphic text
The same soft-UI extrusion, applied to type. The glyphs are the surface colour and
defined only by a dual text-shadow — which traces the outlines of any font, so
it's typeface-agnostic. Best on large display headings (it's low-contrast by nature).
Switch themes and it recolours with the surface.
Raised & softPressed & carvedAny typeface
import { NeuText } from '../components/NeuText'
<NeuText as="h2" variant="raised">Raised & soft</NeuText>
<NeuText variant="pressed">Pressed & carved</NeuText>
<NeuText font="Georgia, serif" depth={3}>Any typeface</NeuText>
Animating it
The extrusion is driven by registered CSS vars (--neu-depth, --neu-blur), animatable
through GSAP or Tailwind/CSS. The star on the left breathes its depth — and
spins when you click it; the word's letters jump in a staggered wave.
// GSAP — tween the registered custom props on the element
gsap.to(shapeRef.current, { '--neu-depth': 15, '--neu-blur': 26, repeat: -1, yoyo: true })
// Tailwind — animate the same vars with utilities (transition + hover, or a keyframe)
<NeuText className="transition-[--neu-depth] hover:[--neu-depth:8px]">Press me</NeuText>
Neumorphic shapes
NeuShape takes the same soft-UI extrusion and applies it to an arbitrary
silhouette — any SVG path, not just a box. The shape is filled with the
surface colour so the body disappears, and two offset drop-shadows (raised) or
an SVG inner-shadow filter (pressed) carry the entire illusion. Colours
default to the theme tokens (--neu-base, --neu-l, --neu-d), so a
<NeuShape> recolours with the active theme the same way <NeuText> does.
Pass a single path via d, or drop arbitrary SVG nodes as children:
import { NeuShape } from '../components/NeuShape'
<NeuShape viewBox="0 0 24 24" d="M12 2 L2 22 H22 Z" depth={6} />
<NeuShape viewBox="0 0 24 24" d="…star path…" variant="pressed" depth={5} />
The depth and blur props feed --neu-depth and --neu-blur as var()
fallbacks, so any Tailwind utility or GSAP tween that targets those custom
properties will animate the extrusion — exactly the same hook NeuText uses.
For drawing your own paths, the Shape Studio (/shape-studio) is the
visual editor: click out a polygon, mix corner / smooth vertices, then copy
the <NeuShape> snippet straight into your code.
Glitch text
An RGB-split glitch built on the neonblade-ui
technique: the text is re-rendered as offset, coloured copies that slice and jitter.
GlitchText is a superset of that component — the documented props below behave
exactly like the original (a two-channel colorA / colorB split via pseudo-elements),
and an additive layers prop stacks any number of colour channels with per-channel
X/Y offsets for richer wordmarks.
The headline below uses a four-colour stack (mode="active", rest="split"). Switch the
navbar theme — it re-tints and the base flips black ↔ white from one tag:
SHINE
The plain two-channel split is the neonblade default — clean at rest, glitches on
hover (the active ones run continuously). Glitch reads best on a dark surface:
import { GlitchText } from '../components/GlitchText'
// Faithful neonblade two-channel split
<GlitchText mode="hover" colorA="pink" colorB="cyan">HOVER</GlitchText>
<GlitchText mode="active" intensity="chaos" speed="frenzy">CHAOS</GlitchText>
<GlitchText mode="active" neon neonFlicker glowColor="cyan">NEON</GlitchText>
// Multi-colour wordmark — `layers` stacks extra channels with X/Y offsets
<GlitchText
mode="active"
rest="split"
layers={[
{ color: '#fb40e9', x: -5, y: 2 }, // pink — far left, slight down
{ color: '#ffe501', x: -2, y: 2 }, // yellow — slight left, slight down
{ color: '#03c3ff', x: 3, y: -3 }, // blue — up and right
]}
>
SHINE
</GlitchText>
Colour palettes
The layers system also ships curated presets drawn from classic glitch art —
pass palette and the spread scales with offset. The trick in all of them is how
offset channels of saturated primaries overlap: complementary pairs (cyan/red) read
as a 3-D split, and CMY channels generate blue/red/green where they cross.
<GlitchText mode="active" rest="split" palette="anaglyph" offset={3}>ERROR</GlitchText>
<GlitchText mode="active" rest="split" palette="cmyk" offset={3}>OOPS</GlitchText>
<GlitchText mode="active" rest="split" palette="spectrum" offset={3}>GLITCH</GlitchText>
Glitch palette (gathered from the references): electric cyan #00f0ff,
red #ff003c, magenta #ff00e5, yellow #ffe600, green #00ff66, blue #2b4bff,
on black or white. Warm hues offset one way, cool hues the other — that opposition
is what sells the split.
Props
The documented neonblade API, all supported:
| Prop | Type | Default | Description |
|---|---|---|---|
text | string | – | String passed to data-text — must match the children text so the pseudo-element channels line up. Defaults to children when it's a plain string. |
mode | "hover" | "active" | "hover" | hover plays the glitch only while hovered; active plays continuously. |
intensity | "subtle" | "normal" | "heavy" | "chaos" | "normal" | Displacement amount of the RGB-split channels. chaos uses a full-cycle keyframe with skew. |
speed | "slow" | "normal" | "fast" | "frenzy" | "normal" | Loop-speed shorthand (2s / 1s / 0.45s / 0.2s). |
customSpeed | string | – | Explicit CSS duration (e.g. "1.5s") — overrides speed. |
colorA | "cyan" | "pink" | "green" | string | "pink" | Colour of the ::before channel text-shadow (preset or CSS colour). |
colorB | "cyan" | "pink" | "green" | string | "cyan" | Colour of the ::after channel text-shadow (preset or CSS colour). |
offset | number | 2 | Horizontal split offset of the RGB channels, in px. |
neon | boolean | false | Adds a neon text-shadow glow around the text. |
neonFlicker | boolean | false | When neon is true, also animates a neon-flicker on the glow. |
glowColor | "cyan" | "pink" | "green" | string | – | Colour of the neon glow (defaults to colorB). |
glitchDuration | number | – | (Deprecated) Legacy loop duration in seconds. Use speed or customSpeed. |
Plus two additions in this template:
| Prop | Type | Default | Description |
|---|---|---|---|
rest | "clean" | "split" | "clean" | clean hides the channels until the glitch plays (neonblade behaviour); split keeps them visible at rest as a frozen split that jitters in place. |
layers | { color, x?, y? }[] | – | Extra colour channels rendered as stacked clones, each with its own X/Y rest offset. When set, replaces the colorA/colorB split — the way multi-colour wordmarks are built. x/y accept a number (px) or any CSS length / custom-property string. |
palette | "anaglyph" | "tiktok" | "cmyk" | "spectrum" | – | A curated channel stack whose spread scales with offset. Shorthand for layers — an explicit layers overrides it. |
mode, intensity, speed, rest are fully configurable — hover or always-on,
subtle to chaos. Reduced-motion users get the frozen stack (the animation is disabled).
Using it
import { Counter } from '../components/Counter'
<Counter>Press the buttons</Counter>
Client components must start with 'use client'. Everything else on the page
stays a React Server Component, so the bundle only ships the interactive bits.
Built-in Nextra components
You also get a full kit out of the box — Callout, Cards, Steps, Tabs,
FileTree, and fenced code blocks with copy buttons, line highlighting and
filenames:
const base = '#e4e9f0'
const intensity = 0.16 // ← highlighted line