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

0

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.

Get started

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.

↻ click me
breathe
// 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:

HOVERSIGNALCHAOSNEON
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.

ERROROOPSGLITCH
<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:

PropTypeDefaultDescription
textstring–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).
customSpeedstring–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).
offsetnumber2Horizontal split offset of the RGB channels, in px.
neonbooleanfalseAdds a neon text-shadow glow around the text.
neonFlickerbooleanfalseWhen neon is true, also animates a neon-flicker on the glow.
glowColor"cyan" | "pink" | "green" | string–Colour of the neon glow (defaults to colorB).
glitchDurationnumber–(Deprecated) Legacy loop duration in seconds. Use speed or customSpeed.

Plus two additions in this template:

PropTypeDefaultDescription
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