What's new Report an issue
GIG Cymru NHS Wales, Digital Health and Care Wales

Colour

How we use colour so it carries meaning consistently, meets accessibility, and works in light and dark across every Single Record product.

How colour is organised

Colour is held in three tiers, and which tier you are allowed to touch depends on what you are doing.

Picking by role rather than by hue is what makes dark mode and future palette changes possible. A component that asks for "the primary interactive colour" keeps working when that colour changes. A component that asks for "Blue 800" does not.

/* Correct: ask for the role. */
.sr-panel {
  background: var(--sr-color-surface-section-cards);
  border: 1px solid var(--sr-color-border-default);
  color: var(--sr-color-text-primary);
}

/* Wrong: a primitive, and a raw hex. */
.sr-panel {
  background: var(--color-blue-50);
  border: 1px solid #d8dde0;
}

Semantic tokens

These are the tokens to build with. Every value below is read from the published token artifact, so this table cannot drift from what ships.

Interactive

TokenValueUse for
--sr-color-interactive-primary #325083 Primary actions and the main brand fill
--sr-color-interactive-primary-hover #1e3050 Hover step for the primary fill
--sr-color-interactive-secondary #1b294a Secondary emphasis and dark chrome such as the masthead
--sr-color-interactive-link #005aa8 Text links in body content
--sr-color-interactive-destructive #d5281b Irreversible actions, paired with a confirmation step
--sr-color-interactive-disabled #828dac Disabled control fills

Surface

TokenValueUse for
--sr-color-surface-background #f4f5f8 The page itself
--sr-color-surface-section-cards #ffffff Large panels and page sections
--sr-color-surface-small-cards #ffffff Cards, menus and popovers
--sr-color-surface-accent #ebf5fa Selected rows and highlighted regions
--sr-color-surface-subtle #f4f5f8 Hover surfaces and quiet fills

Text

TokenValueUse for
--sr-color-text-primary #212b32 Body copy, headings and data values
--sr-color-text-secondary #4c6272 Supporting text, hints and metadata
--sr-color-text-inverse #ffffff Text on a saturated or dark fill
--sr-color-text-disabled #707488 Text in a disabled control

Border

TokenValueUse for
--sr-color-border-subtle #f0f4f5 Row dividers and quiet separators
--sr-color-border-default #d8dde0 Standard component and panel borders
--sr-color-border-strong #768692 Emphasis borders and table header rules
--sr-color-border-focus #0d8bad The focus ring, in both light and dark mode
--sr-color-border-disabled #9ea1af Borders on disabled controls

Contrast

Body text and essential UI must meet WCAG 2.2 AA: 4.5:1 for text, and 3:1 for large text, icons and borders. We target AAA where the pairing allows it. Validate a token against the surface it will actually sit on, not against white by default.

RoleForegroundOn whitePaired surfaceOn that surface
Critical --sr-color-status-critical 6.70:1 --sr-color-status-critical-surface 6.16:1
Success --sr-color-status-success 7.14:1 --sr-color-status-success-surface 6.69:1
Warning --sr-color-status-warning 1.55:1 --sr-color-status-warning-surface 1.49:1
Information --sr-color-status-info 6.94:1 --sr-color-status-info-surface 6.31:1

Ratios are computed at build time from the published token values.

Accents are not text colours

The brand accent --sr-color-brand-accent is an accent only. It does not carry white text at body size, so never use it to fill a button or any surface that needs white text on it. Use --sr-color-interactive-primary for that.

Never colour alone

Colour is never the only signal. This is a hard requirement, not a preference: it is WCAG 1.4.1, and in a clinical context a status that only reads as "red" is a patient-safety problem.

Focus

The focus ring is --sr-color-border-focus at #0d8bad, and it is the same colour in light and dark mode so that focus behaves predictably wherever a control appears. It scores 3.63:1 against the page background and 2.04:1 against the primary fill, so it stays visible on both.

There is no separate focus primitive. An earlier yellow focus colour was replaced by this one and has been removed from the palette, so if you find a yellow focus ring anywhere it is stale code.

.sr-button:focus-visible {
  outline: 3px solid var(--sr-color-border-focus);
  outline-offset: 2px;
}

Dark mode

Dark mode is a second set of values behind the same semantic names. A component written against semantic tokens needs no dark-mode code of its own. Because the names do not change, the rule stays the same: never reach past the semantic layer to a primitive, or the component will not follow the theme.

The dark theme is built and published, but the theme switch on this site is turned off while the colour work is being finalised.


The palette

The raw primitives, rendered live from the published tokens. Reference these from semantic tokens only, never from a component. The number on each swatch is its step.

Blue, NHS Wales blue and the primary brand

900
--color-blue-900#1e3050
850
--color-blue-850#2c3e72
800
--color-blue-800#325083
700
--color-blue-700#3d6199
600
--color-blue-600#4c72ae
500
--color-blue-500#5c6991
400
--color-blue-400#828dac
300
--color-blue-300#aab1c6
200
--color-blue-200#d4d8e2
100
--color-blue-100#eceef3
50
--color-blue-50#f4f5f8

Cyan, DHCW blue, used for the accent and the focus ring

900
--color-cyan-900#0a6a84
850
--color-cyan-850#0c7b99
800
--color-cyan-800#0d8bad
700
--color-cyan-700#12a3c9
600
--color-cyan-600#71accd
500
--color-cyan-500#8dc0da
400
--color-cyan-400#afd4e5
300
--color-cyan-300#d6eaf2
100
--color-cyan-100#ebf5fa
50
--color-cyan-50#f4fafc

Navy

Navy is deliberately a short ramp. It is a narrow utility family used for dark surfaces, disabled borders and disabled text, and steps are added only when a semantic token needs one.

900
--color-navy-900#1b294a
700
--color-navy-700#464c64
500
--color-navy-500#707488
300
--color-navy-300#9ea1af
100
--color-navy-100#cdcfd6

Grey, the neutral UI ramp

900
--color-grey-900#212b32
800
--color-grey-800#2c3a44
700
--color-grey-700#3b4e5b
600
--color-grey-600#4c6272
500
--color-grey-500#768692
400
--color-grey-400#aeb7bd
300
--color-grey-300#c6cdd1
200
--color-grey-200#d8dde0
100
--color-grey-100#f0f4f5
50
--color-grey-50#f7fafa

Red, critical and destructive

900
--color-red-900#5f110a
800
--color-red-800#8b190f
700
--color-red-700#b32014
600
--color-red-600#d5281b
500
--color-red-500#e03a31
400
--color-red-400#ec5e56
300
--color-red-300#f48b85
200
--color-red-200#f9b5b1
100
--color-red-100#fcdbd9
50
--color-red-50#fef3f2

Green, success

900
--color-green-900#003319
800
--color-green-800#004d24
700
--color-green-700#006630
600
--color-green-600#007f3b
500
--color-green-500#1fa66d
400
--color-green-400#4ab88b
300
--color-green-300#7bcaaa
200
--color-green-200#aeddc9
100
--color-green-100#d9efe5
50
--color-green-50#f0faf4

Yellow, warning

900
--color-yellow-900#4a3000
800
--color-yellow-800#6b4400
700
--color-yellow-700#8a5a00
600
--color-yellow-600#b47800
500
--color-yellow-500#f8ca4d
400
--color-yellow-400#face62
300
--color-yellow-300#fbd97f
200
--color-yellow-200#fde8ab
100
--color-yellow-100#fdf3d7
50
--color-yellow-50#fffaeb

Info blue

900
--color-info-blue-900#002e5c
800
--color-info-blue-800#004483
700
--color-info-blue-700#005aa8
600
--color-info-blue-600#0d62a3
500
--color-info-blue-500#267ab8
400
--color-info-blue-400#4e95ca
300
--color-info-blue-300#7eb0d9
200
--color-info-blue-200#aecce8
100
--color-info-blue-100#d6e8f5
50
--color-info-blue-50#eef5fc

Accessibility requirements

RequirementWCAG SCHow Single Record meets itTest method
Text meets contrast against its surface1.4.3Every text and surface pairing is checked before a token ships; the ratios are published on this page.Automated contrast
Non-text UI meets contrast1.4.11Borders, icons and control boundaries are checked at 3:1 against adjacent colours.Automated contrast
Colour is not the only signal1.4.1Status colours pair with text and an icon; selected rows carry a non-colour indicator.Greyscale review
Focus is visible on every surface2.4.7 / 1.4.11One focus colour in both modes, checked against page, card and saturated fills.Keyboard tab, contrast check
Meaning survives a theme change1.4.1Light and dark are two value sets behind one set of semantic names, so meaning is carried by the name.Theme switch review
Users can override colours1.4.12 / 1.4.8Colours are CSS custom properties, so forced-colours and user stylesheets apply cleanly.Forced colours mode