Buttons & actions
Rainbow Button
Vibrant chromatic rainbow border button with animated glowing under-reflection
detent-rainbow-button
Port status
- Catalog status
- implemented
- Origin
- upstream
- Phase
- 2
- Wave
- phase-2-controls
- Group
- Buttons & actions
4.1 KB gzip for the class module
Variants
Recorded states
focus-visiblerecorded state; no setterreduced motionrecorded state; no setter
Usage
Import
import '/components/rainbow-button/define.js';
// or register it yourself
import { DetentRainbowButton } from '/components/rainbow-button/rainbow-button.js';
Attributes
as-childcolor1color2color3color4color5disabledglowhrefsizespeedvariant
Properties
No properties are recorded for this component.
Slots
default
Events
No events are recorded for this component.
Example
Runnable example: site/examples/rainbow-button.ts. The snippet below is generated from the catalogued attributes.
<detent-rainbow-button
as-child
color1="hsl(0 100% 63%)"
color2="hsl(270 100% 63%)"
color3="hsl(210 100% 63%)"
color4="hsl(195 100% 63%)"
color5="hsl(90 100% 63%)"
disabled
glow
href
size="default"
speed="3"
variant="default"
></detent-rainbow-button>
Source
The pinned upstream source for this row:
src/components/ui/RainbowButton.tsxsha256 ec7343408c52…
Native files
The native module and its artifacts:
src/components/rainbow-button/rainbow-button.tssrc/components/rainbow-button/styles.csssrc/components/rainbow-button/define.tsdocs/components/rainbow-button.mdsite/examples/rainbow-button.tstests/browser/rainbow-button.spec.tsevidence/components/rainbow-button.md
API
Boolean attributes follow HTML presence semantics: present means true, absent means false, and disabled="false" still means disabled.
Attributes
| Attribute | Property | Type | Default | Notes |
|---|---|---|---|---|
as-child | asChild | boolean | false | Presence semantics: present means true, absent means false. |
color1 | color1 | string | 'hsl(0 100% 63%)' | Kebab-case attribute; camelCase property. |
color2 | color2 | string | 'hsl(270 100% 63%)' | Kebab-case attribute; camelCase property. |
color3 | color3 | string | 'hsl(210 100% 63%)' | Kebab-case attribute; camelCase property. |
color4 | color4 | string | 'hsl(195 100% 63%)' | Kebab-case attribute; camelCase property. |
color5 | color5 | string | 'hsl(90 100% 63%)' | Kebab-case attribute; camelCase property. |
disabled | — | — | — | Recorded in the catalog as an attribute. |
glow | glow | boolean | true | Presence semantics: present means true, absent means false. |
href | — | — | — | Recorded in the catalog as an attribute. |
size | size | 'default' | 'sm' | 'lg' | 'icon' | 'default' | Kebab-case attribute; camelCase property. |
speed | speed | number | 3 | Kebab-case attribute; camelCase property. |
variant | variant | 'default' | 'outline' | 'default' | Kebab-case attribute; camelCase property. |
Properties
No property-only values are recorded for this component.
Events
No custom events are recorded for this component.
Slots
| Slot | Notes |
|---|---|
default | Consumer content; rendered through a slot, never re-created. |
CSS customisation
- `className` prop is replaced by documented CSS parts/custom properties; no Tailwind in consumers.
- React state/hooks replaced by element-owned state with pre-upgrade property preservation.
- `asChild` becomes a real `<a href>` (the pinned upstream intent mentions a router link or an anchor); `href` is added to the attribute list and javascript: URLs are ignored (PC-11.3).
- `disabled` is added, pinned from the upstream disabled classes and the ButtonHTMLAttributes passthrough; it never fades the label (muted token at full opacity).
- The upstream dark-only #0c0d0e/#18191c interiors are replaced by theme tokens so both variants are legible in light and dark (PC-9.5).
- `rainbowButtonVariants` no longer returns Tailwind classes; it returns the attribute recipe (variant="outline" size="sm") for API parity (PC-1.3).
- The upstream three-layer background-clip stack becomes a real part="border" ring plus an opaque surface, which makes the label contrast provable.
- Hover brightens the chromatic ring only, not the whole control, so label contrast never changes on hover.
What it does
A call-to-action whose 2px ring is a five-stop chromatic gradient panning around an opaque pill, with a blurred rainbow under-reflection. Two variants, four sizes, a real <button> — or a real <a href> when the control navigates.
Upstream behaviour
- Continuous seamless multi-stop chromatic rainbow border animation
- Ambient blurred rainbow underglow shadow reflecting beneath the button surface
- Customizable chromatic color variables (color1 through color5) with vivid defaults
- Zero external library requirements: native CSS animation and self-contained Slot component for asChild support
- Variants: default and outline, with sizes: default, sm, lg, and icon
- Fully accessible: keyboard focus ring, aria attributes pass-through, and prefers-reduced-motion support
Differences from upstream
- `className` prop is replaced by documented CSS parts/custom properties; no Tailwind in consumers.
- React state/hooks replaced by element-owned state with pre-upgrade property preservation.
- `asChild` becomes a real `<a href>` (the pinned upstream intent mentions a router link or an anchor); `href` is added to the attribute list and javascript: URLs are ignored (PC-11.3).
- `disabled` is added, pinned from the upstream disabled classes and the ButtonHTMLAttributes passthrough; it never fades the label (muted token at full opacity).
- The upstream dark-only #0c0d0e/#18191c interiors are replaced by theme tokens so both variants are legible in light and dark (PC-9.5).
- `rainbowButtonVariants` no longer returns Tailwind classes; it returns the attribute recipe (variant="outline" size="sm") for API parity (PC-1.3).
- The upstream three-layer background-clip stack becomes a real part="border" ring plus an opaque surface, which makes the label contrast provable.
- Hover brightens the chromatic ring only, not the whole control, so label contrast never changes on hover.