Detent web components
By Shane Logsdon

Buttons & actions

Rainbow Button

Implemented

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
Get unlimited access

4.1 KB gzip for the class module

Variants

default sizes Small Large +
outline Explore features Small outline Large outline
custom stops, 6s pan Brand palette
glow opt-out
disabled Sold out Unavailable
as-child anchor Browse the catalog

Recorded states

  • focus-visible recorded state; no setter
  • reduced motion recorded 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-child
  • color1
  • color2
  • color3
  • color4
  • color5
  • disabled
  • glow
  • href
  • size
  • speed
  • variant

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.tsx sha256 ec7343408c52…

Native files

The native module and its artifacts:

  • src/components/rainbow-button/rainbow-button.ts
  • src/components/rainbow-button/styles.css
  • src/components/rainbow-button/define.ts
  • docs/components/rainbow-button.md
  • site/examples/rainbow-button.ts
  • tests/browser/rainbow-button.spec.ts
  • evidence/components/rainbow-button.md

API

Boolean attributes follow HTML presence semantics: present means true, absent means false, and disabled="false" still means disabled.

Attributes

Attributes
AttributePropertyTypeDefaultNotes
as-childasChildbooleanfalsePresence semantics: present means true, absent means false.
color1color1string'hsl(0 100% 63%)'Kebab-case attribute; camelCase property.
color2color2string'hsl(270 100% 63%)'Kebab-case attribute; camelCase property.
color3color3string'hsl(210 100% 63%)'Kebab-case attribute; camelCase property.
color4color4string'hsl(195 100% 63%)'Kebab-case attribute; camelCase property.
color5color5string'hsl(90 100% 63%)'Kebab-case attribute; camelCase property.
disabled———Recorded in the catalog as an attribute.
glowglowbooleantruePresence semantics: present means true, absent means false.
href———Recorded in the catalog as an attribute.
sizesize'default' | 'sm' | 'lg' | 'icon''default'Kebab-case attribute; camelCase property.
speedspeednumber3Kebab-case attribute; camelCase property.
variantvariant'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

Slots
SlotNotes
defaultConsumer 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.
Previous: Pull to Refresh Next: Recovery Ledger

Docs

Components

Project