Migrating to CSS variables

Quick references for migrating from old Primer styling systems to new CSS variable primitives

Migrating from sx props (Primer React)

Spacing

Stacks

Stacks are boxes containing flow content in a vertical or horizontal layout. These are usually display: flex or grid or block.

Stack padding

Use these values for the internal padding (including p, px, py, pr, etc shorthands) around the edge of the stack.

sx keywordresolved valueprimitive
00px0
14px--base-size-4
28px--stack-padding-condensed
316px--stack-padding-normal
424px--stack-padding-spacious
532px--base-size-32
640px--base-size-40
748px--base-size-48
864px--base-size-64
980px--base-size-80
1096px--base-size-96
11112px--base-size-112
12128px--base-size-128
Stack margin
Prefer not using `margin` since it leaks space outside of components. Try to convert margins to container `padding` and/or flex layout `gap`.

See padding values above; there are no margin primitives.

Stack content spacing

This is typically the CSS gap in flex (with flex-direction: column) or grid layouts. Could also be the margin between items that have not been updated to flexbox/grid.

sx keywordresolved valueprimitive
00px0
14px--base-size-4
28px--stack-gap-condensed
316px--stack-gap-normal
424px--stack-gap-spacious
532px--base-size-32
640px--base-size-40
748px--base-size-48
864px--base-size-64
980px--base-size-80
1096px--base-size-96
11112px--base-size-112
12128px--base-size-128

Control stacks

Control stacks are horizontal (inline) rows containing inline interactive items next to each other. For example, a set of buttons or labels. These are usually display: flex or inline-flex with flex-direction: row.

The size of the control stack depends on the size of the controls inside of it. For example, a stack containing a
small
icon button is a 'small' stack.
Control stack padding / margin

Use the same padding and margin values as for a vertical Stack.

Control stack content spacing

The gap property in flex layouts, or item margin in older layouts.

sx keywordresolved valueprimitive
00px0
14px--base-size-4
28px--controlStack-small-gap-condensed
--controlStack-medium-gap-condensed
--controlStack-large-gap-condensed
316px--controlStack-small-gap-spacious
--controlStack-medium-gap-spacious
--controlStack-large-gap-spacious
424px--base-size-24
532px--base-size-32
640px--base-size-40
748px--base-size-48
864px--base-size-64
980px--base-size-80
1096px--base-size-96
11112px--base-size-112
12128px--base-size-128

Controls

Controls are Buttons, Labels, etc -- small building block elements.

These values must be resolved on a case-by-case basis because they are different for each size of control, each density level, and for the top/bottom vs the sides. See the primitives list to find a good value or just use --base-size values for now.

Colors

Canvas

sx keywordprimitive
canvas.default--bgColor-default
canvas.overlay--overlay-bgColor
canvas.inset--bgColor-inset
canvas.subtle--bgColor-muted

Foreground

sx keywordprimitive
fg.default--fgColor-default
fg.muted--fgColor-muted
fg.subtleeliminated, use --fgColor-muted instead
fg.onEmphasis--fgColor-onEmphasis

Border

sx keywordprimitive
border.default--borderColor-default
border.muted--borderColor-muted
border.subtleeliminated, use --borderColor-muted instead

Accent

sx keywordprimitive
accent.fg--fgColor-accent
accent.emphasis--bgColor-accent-emphasis
accent.muted--borderColor-accent-muted
accent.subtle--bgColor-accent-muted

Success, Attention, Severe, Danger, Open, Closed, Done, Sponsors

sx keywordprimitive
{name}.fg--fgColor-{name}
{name}.emphasis--bgColor-{name}-emphasis
{name}.muted--borderColor-{name}-muted
{name}.subtle--bgColor-{name}-muted

Fonts

Font size

Try to use the one that applies to the type of text you are styling:

Titles

Heading or similar components.

sx keywordresolved valueprimitive
012px--base-size-12
114px--base-size-14
216px--text-title-size-small
320px--text-title-size-medium
424px--base-size-24
532px--text-title-size-large
640px--base-size-40
748px--base-size-48
856px--base-size-56
Body text
sx keywordresolved valueprimitive
012px--text-body-size-small
114px--text-body-size-medium
216px--text-body-size-large
320px--base-size-20
424px--base-size-24
532px--base-size-32
640px--base-size-40
748px--base-size-48
856px--base-size-56

Font family

sx keywordprimitive
normal--fontStack-system or explicitly --fontStack-sansSerif
mono--fontStack-monospace

Borders

Border color

See: Border colors

Border width

Prefer these primitives instead of previously used numbers or plain pixel values:

sx keywordresolved valueprimitive
00px0
11px--borderWidth-thin
2px--borderWidth-thick
3px--borderWidth-thicker

Border radius

sx keywordresolved valueprimitive
00px0
13px--borderRadius-small
26px--borderRadius-medium
12px--borderRadius-large
3a lot--borderRadius-full

Sizes and Breakpoints

These are typically used for breakpoints, heights and widths.

For overlays (like dialogs), prefer the [new overlay primitives](https://primer.style/foundations/primitives/size#overlay). These sizes are not a 1:1 mapping with the old keywords.
CSS variables cannot be used in `@media` or `@container` query expressions. The plain pixel value must be used instead. Stay tuned for future media query support.
sx breakpoint keywordsx size keywordresolved valueprimitive
320px--breakpoint-xsmall
0size.small544px--breakpoint-small
1size.medium768px--breakpoint-medium
2size.large1012px--breakpoint-large
3size.xlarge1280px--breakpoint-xlarge
1400px--breakpoint-xxlarge

Migrating from SCSS Variables

Most legacy SCSS variables from Primer CSS have new CSS variable replacements.

For values that have no replacement listed, use the raw value or find a replacement that is close in value.

Legacy scss variableNew css variable
$h00-size-mobile--text-display-size
$h0-size-mobile--text-title-size-large
$h1-size-mobile26px deprecated
$h2-size-mobile22px deprecated
$h3-size-mobile18px deprecated
$h00-size--base-size-48
$h0-size--text-display-size
$h1-size--text-title-size-large
$h2-size--base-size-24
$h3-size--text-title-size-medium
$h4-size--text-title-size-small
$h5-size--text-body-size-medium
$h6-size--text-body-size-small
$font-size-small--text-body-size-small
$font-weight-bold--base-text-weight-semibold
$font-weight-semibold--base-text-weight-medium
$font-weight-normal--base-text-weight-normal
$font-weight-light--base-text-weight-light
$lh-condensed-ultra1`
$lh-condensed1.25`
$lh-default1.5`
$body-font--fontStack-system
$mono-font--fontStack-monospace
$body-font-size--text-body-size-medium
$body-line-height--text-body-lineHeight-medium
$spacer--base-size-8
$spacer-00 deprecated
$spacer-1--base-size-4
$spacer-2--base-size-8
$spacer-3--base-size-16
$spacer-4--base-size-24
$spacer-5--base-size-32
$spacer-6--base-size-40
$spacer-7--base-size-48
$spacer-8--base-size-64
$spacer-9--base-size-80
$spacer-10--base-size-96
$spacer-11--base-size-112
$spacer-12--base-size-128
$em-spacer-10.0625em deprecated
$em-spacer-20.125em deprecated
$em-spacer-30.25em deprecated
$em-spacer-40.375em deprecated
$em-spacer-50.5em deprecated
$em-spacer-60.75em deprecated
$size--base-size-16
$size-00 deprecated
$size-1--base-size-16
$size-2--base-size-20
$size-3--base-size-24
$size-4--base-size-28
$size-5--base-size-32
$size-6--base-size-40
$size-7--base-size-48
$size-8--base-size-64
$container-width980px deprecated
$grid-gutter10px deprecated
$width-xs0 deprecated
$width-sm--breakpoint-small
$width-md--breakpoint-medium
$width-lg--breakpoint-large
$width-xl--breakpoint-xlarge
$container-sm--breakpoint-small
$container-md--breakpoint-medium
$container-lg--breakpoint-large
$container-xl--breakpoint-xlarge
$viewport-narrow--viewportRange-narrow
$viewport-regular--viewportRange-regular
$viewport-wide--viewportRange-wide
$border-width--borderWidth-thin
$border-stylesolid deprecated
$bordersolid var(--borderWidth-thin) var(--borderColor-default)
$border-remsolid var(--borderWidth-thin) var(--borderColor-default)
$border-radius-1--borderRadius-small
$border-radius-2--borderRadius-medium
$border-radius-38px --borderRadius-medium`
$border-radius--borderRadius-small