PDS ships color in two layers. 119 core steps are the palette. 153 alias tokens are the decisions already made with it — color.Text.Primary, color.Background.Button.Primary Hover — and each one resolves to a core step. Nothing prevents you from typing a core step directly, so the only thing separating the palette from the system is which layer you reach for.
Core palette
Section titled “Core palette”119 core tokens across 8 families. Each step is labelled in whichever of black or white meets WCAG AA against it, which today is every step.
Purple
color.Core.Purple.*- 50#F4F5FF
- 100#E9EAFF
- 150#DEE0FF
- 200#D3D5FF
- 250#C8CBFE
- 300#BDC0FE
- 350#B2B6FE
- 400#A7ABFE
- 450#7A7FFD
- 500#7379FD
- 600#3F48FD
- 700#0B16FC
- 800#020CD0
- 900#02099C
- 1000#010668
- 1100#010334
Red
color.Core.Red.*- 50#FEF3F2
- 100#FDE7E4
- 150#FCDBD7
- 200#FBCFCA
- 250#FAC2BC
- 300#F9B6AF
- 350#F8AAA1
- 400#F79E94
- 500#F47466
- 600#F04B38
- 700#E62711
- 800#B81F0E
- 900#8A170A
- 1000#5C0F07
- 1100#2E0803
Orange
color.Core.Orange.*- 50#FFF9F1
- 100#FFF4E3
- 150#FFEED4
- 200#FFE9C6
- 250#FEE3B8
- 300#FEDDAA
- 350#FED89B
- 400#FED28D
- 500#FEBF5C
- 600#FDAB2B
- 700#F59602
- 800#C47802
- 900#935A01
- 1000#623C01
- 1100#311E00
Yellow
color.Core.Yellow.*- 50#FDFFF1
- 100#FBFFE4
- 150#F9FFD6
- 200#F7FFC9
- 250#F4FEBB
- 300#F2FEAD
- 350#F0FEA0
- 400#EEFE92
- 500#E6FE60
- 600#DFFD2F
- 700#D3F802
- 800#A9C602
- 900#7F9501
- 1000#556301
- 1100#2A3200
Green
color.Core.Green.*- 50#F1FCF8
- 100#E2F9F0
- 150#D4F5E9
- 200#C6F2E2
- 250#B7EFDA
- 300#A9ECD3
- 350#9AE8CB
- 400#8CE5C4
- 500#66DCB1
- 600#41D49D
- 700#2BBC86
- 800#22966B
- 900#1A7150
- 1000#114B36
- 1100#09261B
Teal
color.Core.Teal.*- 50#F3FEFF
- 100#E6FDFF
- 150#DAFBFF
- 200#CDFAFF
- 250#C1F9FE
- 300#B4F8FE
- 350#A8F6FE
- 400#9BF5FE
- 500#68F0FD
- 600#36EBFD
- 700#03E6FC
- 800#02B8CA
- 900#028A98
- 1000#015C65
- 1100#012E33
Blue
color.Core.Blue.*- 50#F1F6FF
- 100#E3EEFF
- 150#D4E5FF
- 200#C6DDFF
- 250#B8D4FE
- 300#AACBFE
- 350#9BC3FE
- 400#8DBAFE
- 500#5C9CFE
- 600#2B7FFD
- 700#0263F5
- 800#024FC4
- 900#013B93
- 1000#012862
- 1100#001431
Slate
color.Core.Slate.*- 25#F9F9FA
- 50#F5F5F6
- 100#F1F1F2
- 200#E2E2E3
- 300#DBDBDB
- 400#CCCCCC
- 500#BDBDBD
- 600#A0A0A0
- 700#848484
- 800#707070
- 900#565656
- 1000#434343
- 1100#313131
The alias layer skips the half-steps
Section titled “The alias layer skips the half-steps”69 of the 119 core steps are referenced by an alias. The other 50 have no decision attached, and they are not scattered. 30 of them are the half-steps — 50, 150, 250, 350, and purple’s 450 — and another seven are step 1100, the darkest, in every hue. Slate’s 1100 is the exception, because it is color.Text.Primary.
So the alias layer was built on the round steps and left the ones between them alone. The half-steps still render in the matrix above and have never been the answer to a question. Reach for one and you are making the decision rather than applying it, and the package has nowhere to record what you decided.
Background holds 85 of the 153 alias names
Section titled “Background holds 85 of the 153 alias names”The alias layer is lopsided: Background has 85 tokens, Border 45, Text 14, and Primary 9. The reason is how it grew. Background names a surface per component per state, so color.Background.Label.Purple Disabled and color.Background.Button.Outline Hover are separate tokens rather than one rule applied twice. A background you need probably already has a token. A text color for a state nobody has built probably does not — fourteen names cover every piece of text in the product.
The CSS build keeps the alias-to-core link and the JavaScript build resolves it
Section titled “The CSS build keeps the alias-to-core link and the JavaScript build resolves it”In dist/css, 147 of the 153 alias properties are a var() pointing at another property, and the chain is intact: --color-background-button-primary is var(--color-primary-purple), which is var(--color-core-purple-600). Change one step and everything downstream of it moves.
In dist/js, the same token is a flat string. Color.BackgroundButtonPrimary is #3F48FD, and nothing in the value records that it came from purple 600. So a search for every consumer of a core step finds them in stylesheets and misses them in JavaScript, and the only complete map of alias to core is the 189 references in the Figma token file.
Six alias tokens have no core step behind them: color.Primary.Black and color.Primary.White are literal hex, and the four transparent button backgrounds are transparent — spelled rgba(0, 0, 0, 0) in CSS and transparent in JavaScript.
There is no dark palette in the tokens
Section titled “There is no dark palette in the tokens”The tokens define one color per name. color.Background.Primary is white, in every theme, because the package has no concept of a theme.
Dark mode in the React library is therefore a second map, written by hand in @persona/design-system, and it reaches past the alias layer to core steps: its dark background is Color.CoreSlate1000 and its dark secondary text is Color.CoreSlate500. Neither is an alias, so neither appears in the alias layer as a dark value, and the two maps can disagree without anything detecting it.
The swatch labels are computed contrast against black and white
Section titled “The swatch labels are computed contrast against black and white”Every step above is labeled in whichever of black or white meets WCAG AA against it, computed from the token at build time, and where neither reaches 4.5:1 the swatch says so. That is contrast for the swatch against black or white, and nothing else. It does not tell you the contrast of two tokens you are about to put together, and it is not a conformance claim — see Accessibility for what PDS does and does not verify.
Was this page helpful?