Components
Reusable UI patterns shared across ONCE products. Each component uses the brand color tokens and follows the dark-first design approach.
Buttons
Primary Button
Solid background with --once-blue. Used for the most important action on any screen.
<Button className="bg-once-blue hover:bg-once-blue/80 text-once-white">
Get Started
</Button>Outline Button
Transparent with a border. Used for secondary actions that sit alongside a primary button.
<Button
variant="outline"
className="border-once-blue/40 text-once-white hover:bg-once-blue/10"
>
Learn More
</Button>Button Pair
When two actions appear together, the primary button leads:
Cards
Cards use a translucent blue background with a subtle border. They elevate slightly on hover.
<Card className="bg-once-blue/10 border-once-blue/20">
{/* Content */}
</Card>Release Manager
Upload, validate, and distribute your music to all major platforms in one flow.
Card Grid
Cards arrange in a responsive grid using auto-fit with a minimum of 240px per column.
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 12px;
}Text Hierarchy
Text hierarchy on dark backgrounds is built using opacity on --once-white, not separate color values.
| Level | Class | Opacity | Typical use |
|---|---|---|---|
| Primary | text-once-white | 100% | Headings, key labels |
| Secondary | text-once-white/70 | 70% | Body paragraphs |
| Muted | text-once-white/60 | 60% | Descriptions |
| Subtle | text-once-white/50 | 50% | Captions, timestamps |
| Very subtle | text-once-white/40 | 40% | Decorative labels |
Borders
Borders follow a three-step scale using --once-blue with opacity:
| State | Class | Value |
|---|---|---|
| Default | border-once-blue/20 | Resting card and divider borders |
| Hover | border-once-blue/40 | Hovered cards and interactive elements |
| Active | border-once-blue | Focused / selected elements |
Badges
Badges are pill-shaped labels used for status communication.
Early Access Badge
Animated glow effect with a pulsing dot:
Patron Badge
Purple tint for patron-exclusive features:
Card Badges
Smaller badges that sit inside card headers:
<div className="card-header-row">
<h3>Feature Name</h3>
<span className="card-badge">PATRON</span>
</div>Mobile Bottom Sheet (Slide-Up Modal)
On mobile screens, modals and dialogs use a bottom sheet pattern — the panel slides up from the bottom of the viewport and anchors there, with only the top corners rounded. On larger screens (md and above) the same modal centers in the viewport with full border-radius as usual.
This pattern is used for every modal and dialog on mobile. It keeps the content within thumb reach, feels native on phones, and avoids tiny centered panels on narrow viewports.
How it works
The technique is pure Tailwind — no JS animations required:
| Concern | Mobile | Desktop (md:) |
|---|---|---|
| Alignment | items-end (flex-end → bottom) | md:items-center (centered) |
| Padding | p-0 (edge-to-edge) | md:p-4 or md:p-6 |
| Border-radius | rounded-t-2xl (top corners only) | md:rounded-xl (all corners) |
| Max height | max-h-[90vh] | md:max-h-[80vh] or md:max-h-none |
Example
{/* Backdrop */}
<div
className="fixed inset-0 z-50 bg-black/40 backdrop-blur-sm flex items-end md:items-center justify-center p-0 md:p-4"
onClick={onClose}
>
{/* Panel */}
<div
className="w-full max-w-lg bg-white rounded-t-2xl md:rounded-xl shadow-2xl border border-gray-100 flex flex-col max-h-[90vh] md:max-h-[80vh] overflow-hidden"
onClick={(e) => e.stopPropagation()}
>
{/* Header */}
<div className="flex items-center justify-between px-5 py-4 border-b border-gray-100">
<h3 className="text-lg font-semibold">Modal Title</h3>
<button onClick={onClose} className="p-2 rounded hover:bg-gray-100">✕</button>
</div>
{/* Scrollable content */}
<div className="flex-1 overflow-y-auto p-5">
{/* ... */}
</div>
{/* Footer */}
<div className="border-t border-gray-200 bg-gray-50 px-5 py-3 flex justify-end gap-2">
<button onClick={onClose}>Cancel</button>
<button>Confirm</button>
</div>
</div>
</div>Key classes at a glance
- Backdrop:
fixed inset-0 … flex items-end md:items-center justify-center p-0 md:p-4 - Panel:
rounded-t-2xl md:rounded-xl max-h-[90vh] md:max-h-[80vh]
On mobile the panel hugs the bottom edge with rounded top corners; on desktop it floats centered with uniform border-radius.
Status Colors
Use the utility colors for feedback states — never for decoration.
—mr-approval—mr-warning—mr-rejection