Foundations

Color

The SWSH palette and the roles that give it purpose, in dark and light.

SWSH Orange

#EE421B

Light orange

#FFB78A

Dark orange

#2D0800

Brand white

#EFEFEF

Light gray

#DEDEDE

Gray

#A5A5A5

Medium gray

#222222

Dark gray

#101010

Brand black

#040404

The five ramps run from 50, the lightest step, to 950, the darkest, with 500 as the base. Each published brand hex is an exact anchor step; every other step is interpolated in OKLCH between its nearest anchors.

50100200300400500600700800900950
gray
orange
red
green
amber

Red, green, and amber support status UI and have no brand source.

White and black alpha ramps use eight-digit hex; the last pair represents opacity. Judge them on their actual backdrop, not as opaque colors.

whiteAlpha
5%#FFFFFF0D
10%#FFFFFF1A
20%#FFFFFF33
30%#FFFFFF4D
40%#FFFFFF66
50%#FFFFFF80
60%#FFFFFF99
70%#FFFFFFB3
80%#FFFFFFCC
90%#FFFFFFE6
blackAlpha
5%#0000000D
10%#0000001A
20%#00000033
30%#0000004D
40%#00000066
50%#00000080
60%#00000099
70%#000000B3
80%#000000CC
90%#000000E6

True white and black are for logo variants and alpha bases. For surfaces, use a role such as bg.canvas or bg.surface rather than a primitive; the light theme’s bg.surface is the role that resolves to white.

A primitive says what a value is; a role says what it is for. Every role references a palette primitive through THEME_REFS.

Marker 1
Marker 2
Marker 3
Riverside weekend
Shared album
Shared
Marker 5
Friday — Sunday
Marker 4
Every moment, together
Marker 1bg.canvasblack
Marker 2bg.surfacegray[950]
Marker 3text.primarygray[100]
Marker 4text.mutedgray[400]
Marker 5accent.defaultorange[500]
Marker 6fill.raised.defaultgray[900]

bg

Canvas, surfaces, and the scrim.

fill

Interactive surfaces with default, hover, and pressed states.

text

Primary, muted, disabled, and inks for named fills.

border

Subtle hairlines, default dividers, and strong emphasis.

accent

The brand orange.

status

Success, warning, and danger indicators.

tint

Soft tinted fills with a matching ink — badge tones and the card icon square.

Card and search surfaces

Card and web SearchResults/Root share getCardSurface from swshd/tokens: fill.raised.default in dark mode and bg.surface in light mode. Filled SearchBar/Field shares Input's interactive surface: fill.raised.hover at rest and fill.raised.pressed on hover or focus. Compose these parts without overriding their backgrounds.

Native search results and the full-screen search header use bg.canvas, matching the app background. Recent rows are transparent at rest; touch feedback encloses the query and its secondary action in one shared row. Selected items retain their selection fill.

Overlay frames

Dialogs, sheets, and alerts use OVERLAY_SURFACE_TOKENS from swshd/tokens. Their frame uses bg.elevated; a search card inside the frame still uses the shared card surface.

Rows on surfaces

Use fill.subtle on bg.surface for rows. fill.selected is the active row’s steady backdrop, not another hover state.

Disabled is not a color

Touchable applies opacity to disabled controls, so no fill has a disabled state. text.disabled is the ink for disabled text.

Every role, its primitive reference, and resolved color in the selected theme.

Theme
bg
RolePrimitiveHex
black
gray[950]
gray[950]
black
blackAlpha[50]
fill
RolePrimitiveHex
gray[100]
gray[200]
gray[300]
gray[900]
gray[800]
gray[700]
transparent
whiteAlpha[10]
whiteAlpha[20]
red[600]
red[700]
red[800]
transparent
whiteAlpha[5]
whiteAlpha[10]
gray[800]
gray[800]
gray[800]
text
RolePrimitiveHex
gray[100]
gray[400]
white
gray[600]
gray[950]
gray[950]
gray[100]
border
RolePrimitiveHex
gray[900]
gray[800]
gray[400]
accent
RolePrimitiveHex
orange[500]
orange[300]
orange[950]
status
RolePrimitiveHex
green[500]
amber[500]
red[500]
tint
RolePrimitiveHex
orange[950]
orange[300]
green[950]
green[400]
amber[950]
amber[500]
red[950]
red[400]

Every role exists in both built-in themes. A nested provider can re-theme a subtree; custom themes use createSwshdTheme over a built-in base.

dark theme
Riverside weekend
Shared album
Shared
Friday — Sunday
Every moment, together
light theme
Riverside weekend
Shared album
Shared
Friday — Sunday
Every moment, together
import SwshdThemeProvider from "swshd/ThemeProvider";

<SwshdThemeProvider theme="light">
  <AlbumPreview />
</SwshdThemeProvider>

Ratios cover the canvas inks, on-accent ink, and every fill state. Alpha fills are composited over their intended surface before they are graded.

Theme
PairRatioGrade
Aa
text.primary on bg.canvas
18.26:1
AAA
Aa
text.muted on bg.canvas
8.53:1
AAA
Aa
text.onAccent on accent.default
5.30:1
AA
Aa
text.inverse on fill.inverse.default
17.83:1
AAA
Aa
text.inverse on fill.inverse.hover
15.24:1
AAA
Aa
text.inverse on fill.inverse.pressed
11.39:1
AAA
Aa
text.primary on fill.raised.default
16.55:1
AAA
Aa
text.primary on fill.raised.hover
13.84:1
AAA
Aa
text.primary on fill.raised.pressed
9.16:1
AAA
Aa
text.primary on fill.ghost.default
composited over bg.canvas
18.26:1
AAA
Aa
text.primary on fill.ghost.hover
composited over bg.canvas
15.14:1
AAA
Aa
text.primary on fill.ghost.pressed
composited over bg.canvas
10.99:1
AAA
Aa
text.onDanger on fill.danger.default
5.31:1
AA
Aa
text.onDanger on fill.danger.hover
7.74:1
AAA
Aa
text.onDanger on fill.danger.pressed
11.09:1
AAA
Aa
text.primary on fill.subtle.default
composited over bg.surface
17.83:1
AAA
Aa
text.primary on fill.subtle.hover
composited over bg.surface
16.42:1
AAA
Aa
text.primary on fill.subtle.pressed
composited over bg.surface
14.50:1
AAA
Aa
text.primary on fill.selected.default
13.84:1
AAA
Aa
text.primary on fill.selected.hover
13.84:1
AAA
Aa
text.primary on fill.selected.pressed
13.84:1
AAA
AAA ≥ 7:1 · AA ≥ 4.5:1 · AA Large ≥ 3:1 · Fail < 3:1
colors.text.primary
Do

Use a role.

#EE421B
Don't

Copy a hex.

Do

Fill buttons with their variant role.

Don't

Fill a button with SWSH Orange.

colors.bg.surface
Do

Build surfaces from bg roles.

colors.white
Don't

Use white or black as a surface.

import { useSwshdTheme } from "swshd/ThemeProvider";
import Text from "swshd/Text";

const { colors } = useSwshdTheme();
<Text variant="body-md" color={colors.text.primary}>
  Share the whole night
</Text>