Open DS

Naming

Five questions every design system answers about naming. These are Multi-brand’s answers, and each one points back to the reasons that chose it.

View all 71 naming tokens ↓

The reasons this scheme answers from

  • R1Business and productSells and converts, many
  • R2Team and deliveryA platform team, every month

Question 1

What gets a name?

  • Tokens
  • Tokens and component keys (chosen)

Why Multi-brand picks it: Components get their own keys, shared by every brand.

becauseR1

button{color.action.primary.@} · {color.action.primary.hover} · {color.text.on-action} · {color.action.secondary.@} · {color.action.secondary.hover} · {color.text.primary} · {color.border.strong} · {color.surface.sunken} · {color.text.link} · {size.control.default} · {space.inset.control-x} · {radius.control} · {type.label.font-size} · {type.label.font-weight} · {color.border.focus} · {size.icon} · {color.disabled.surface} · {color.disabled.text} · {color.disabled.border}
input{color.surface.default} · {color.border.strong} · {color.border.focus} · {color.text.primary} · {color.text.muted} · {size.control.default} · {space.inset.control-x} · {radius.control} · {type.body.font-size} · {color.disabled.surface} · {color.disabled.border} · {color.disabled.text}
control{color.action.primary.@} · {color.border.strong} · {color.surface.default} · {radius.badge}
badge{radius.badge} · {space.gap.tight} · {type.caption.font-size} · {color.surface.sunken} · {color.text.secondary} · {color.status.success.subtle} · {color.status.success.@} · {color.status.warning.subtle} · {color.status.warning.@} · {color.status.danger.subtle} · {color.status.danger.@} · {color.status.info.subtle} · {color.status.info.@}
card{color.surface.default} · {color.border.default} · {radius.container} · {space.inset.container} · {elevation.card}
table{color.surface.sunken} · {size.row} · {space.inset.cell-x} · {color.border.default} · {color.surface.selected} · {type.data.font-size}
tabs{color.action.primary.@} · {color.text.secondary} · {color.text.primary}
overlay{color.surface.raised} · {radius.container} · {elevation.overlay} · {color.surface.scrim} · {size.control.default}
tooltip{color.surface.inverse} · {color.text.inverse}
transition{motion.duration.feedback} · {motion.easing.standard}

Question 2

How many token tiers?

  • Two
  • Three (chosen)

Why Multi-brand picks it: Primitives, semantics and component keys.

becauseR2

action primary2
color text6
action secondary2
color border3
color surface6
size control1
space inset3
radius3
type label2
size2
color disabled3
type body1
space gap1
type caption1
status success2
status warning2
status danger2
status info2
elevation2
type data1
motion duration1
motion easing1

Question 3

How are decisions named?

  • By role (chosen)
  • By component

Why Multi-brand picks it: Role names stay the same in every brand.

becauseR1

  • By role
  • from color.action.primary
  • from color.text
  • from color.action.secondary
  • from color.border
  • from color.surface
  • from size.control
  • from space.inset
  • from radius
  • from type.label
  • from size
  • from color.disabled
  • from type.body
  • from space.gap
  • from type.caption
  • from color.status.success
  • from color.status.warning
  • from color.status.danger
  • from color.status.info
  • from elevation
  • from type.data
  • from motion.duration
  • from motion.easing

Decisions point at primitives, so the rule lives in one place.

Question 4

How are names written?

  • Lowercase words in paths (chosen)
  • camelCase

Why Multi-brand picks it: Lowercase paths read the same everywhere.

becauseR2

  • button
    primary.background.@
    → color.action.primary.@
    primary.background.hover
    → color.action.primary.hover
    primary.label
    → color.text.on-action
    secondary.background.@
    → color.action.secondary.@
    secondary.background.hover
    → color.action.secondary.hover
    secondary.label
    → color.text.primary
    secondary.border
    → color.border.strong
    ghost.background-hover
    → color.surface.sunken
    ghost.label
    → color.text.link
    height
    → size.control.default
    padding-x
    → space.inset.control-x
    radius
    → radius.control
    font-size
    → type.label.font-size
    font-weight
    → type.label.font-weight
    focus-ring
    → color.border.focus
    icon-size
    → size.icon
    disabled.background
    → color.disabled.surface
    disabled.label
    → color.disabled.text
    disabled.border
    → color.disabled.border
  • input
    background
    → color.surface.default
    border.@
    → color.border.strong
    border.focus
    → color.border.focus
    text
    → color.text.primary
    placeholder
    → color.text.muted
    height
    → size.control.default
    padding-x
    → space.inset.control-x
    radius
    → radius.control
    font-size
    → type.body.font-size
    disabled.background
    → color.disabled.surface
    disabled.border
    → color.disabled.border
    disabled.text
    → color.disabled.text
  • control
    checked
    → color.action.primary.@
    track
    → color.border.strong
    thumb
    → color.surface.default
    radius
    → radius.badge
  • badge
    radius
    → radius.badge
    padding-x
    → space.gap.tight
    font-size
    → type.caption.font-size
    neutral.background
    → color.surface.sunken
    neutral.label
    → color.text.secondary
    success.background
    → color.status.success.subtle
    success.label
    → color.status.success.@
    warning.background
    → color.status.warning.subtle
    warning.label
    → color.status.warning.@
    danger.background
    → color.status.danger.subtle
    danger.label
    → color.status.danger.@
    info.background
    → color.status.info.subtle
    info.label
    → color.status.info.@
  • card
    background
    → color.surface.default
    border
    → color.border.default
    radius
    → radius.container
    padding
    → space.inset.container
    shadow
    → elevation.card
  • table
    header-background
    → color.surface.sunken
    row-height
    → size.row
    cell-padding-x
    → space.inset.cell-x
    row-border
    → color.border.default
    row-selected
    → color.surface.selected
    font-size
    → type.data.font-size
  • tabs
    indicator
    → color.action.primary.@
    label.@
    → color.text.secondary
    label.active
    → color.text.primary
  • overlay
    background
    → color.surface.raised
    radius
    → radius.container
    shadow
    → elevation.overlay
    scrim
    → color.surface.scrim
    item-height
    → size.control.default
  • tooltip
    background
    → color.surface.inverse
    label
    → color.text.inverse
  • transition
    duration
    → motion.duration.feedback
    easing
    → motion.easing.standard

Question 5

What do components read?

  • Component keys (chosen)
  • Semantic tokens

Why Multi-brand picks it: Components never change; brand primitives do.

becauseR1

  • button
  • input
  • control
  • badge
  • card
  • table
  • tabs
  • overlay
  • transition

When to use

  • A value with no tokenUse: The closest semantic token, then ask for a new one. Not: A raw value or a brand primitive in the component. A raw value shows the same in every brand, so it breaks the theme.

All naming tokens

71 tokens · each decision and the primitive it points to

  • color.action.primary · 2color.action.primary.@#0F766Ecolor.action.primary.hover#0B5B55
  • color.text · 6color.text.on-action#FFFFFFcolor.text.primary#0F172Acolor.text.link#0B5B55color.text.muted#4B5A6Fcolor.text.secondary#334155color.text.inverse#FFFFFF
  • color.action.secondary · 2color.action.secondary.@#FFFFFFcolor.action.secondary.hover#F1F5F9
  • color.border · 3color.border.strong#64748Bcolor.border.focus#0F766Ecolor.border.default#E2E8F0
  • color.surface · 6color.surface.sunken#F1F5F9color.surface.default#FFFFFFcolor.surface.selected#E0F2F1color.surface.raised#FFFFFFcolor.surface.scrim#0000008Ccolor.surface.inverse#0F172A
  • size.control · 1size.control.default2.75rem · 44px
  • space.inset · 3space.inset.control-x1rem · 16pxspace.inset.container1.5rem · 24pxspace.inset.cell-x1rem · 16px
  • radius · 3radius.control0.25rem · 4pxradius.badge0.25rem · 4pxradius.container0.5rem · 8px
  • type.label · 2type.label.font-size0.875rem · 14pxtype.label.font-weight600
  • size · 3size.control.default2.75rem · 44pxsize.icon1rem · 16pxsize.row3rem · 48px
  • color.disabled · 3color.disabled.surface#F1F5F9color.disabled.text#64748Bcolor.disabled.border#E2E8F0
  • type.body · 1type.body.font-size1rem · 16px
  • space.gap · 1space.gap.tight0.5rem · 8px
  • type.caption · 1type.caption.font-size0.8125rem · 13px
  • color.status.success · 2color.status.success.subtle#E3F4EAcolor.status.success.@#1F7A3A
  • color.status.warning · 2color.status.warning.subtle#FFF3D6color.status.warning.@#8A5600
  • color.status.danger · 2color.status.danger.subtle#FDE7E7color.status.danger.@#C42B2B
  • color.status.info · 2color.status.info.subtle#E1ECFFcolor.status.info.@#083C93
  • elevation · 2elevation.card0px 2px 8px 0px #0F172A14elevation.overlay0px 12px 32px 0px #0F172A29
  • type.data · 1type.data.font-size1rem · 16px
  • motion.duration · 1motion.duration.feedback200ms
  • motion.easing · 1motion.easing.standardcubic-bezier(0.2, 0, 0, 1)
  • Decisions · 71component.button.primary.background.@{color.action.primary.@}component.button.primary.background.hover{color.action.primary.hover}component.button.primary.label{color.text.on-action}component.button.secondary.background.@{color.action.secondary.@}component.button.secondary.background.hover{color.action.secondary.hover}component.button.secondary.label{color.text.primary}component.button.secondary.border{color.border.strong}component.button.ghost.background-hover{color.surface.sunken}component.button.ghost.label{color.text.link}component.button.height{size.control.default}component.button.padding-x{space.inset.control-x}component.button.radius{radius.control}component.button.font-size{type.label.font-size}component.button.font-weight{type.label.font-weight}component.button.focus-ring{color.border.focus}component.button.icon-size{size.icon}component.button.disabled.background{color.disabled.surface}component.button.disabled.label{color.disabled.text}component.button.disabled.border{color.disabled.border}component.input.background{color.surface.default}component.input.border.@{color.border.strong}component.input.border.focus{color.border.focus}component.input.text{color.text.primary}component.input.placeholder{color.text.muted}component.input.height{size.control.default}component.input.padding-x{space.inset.control-x}component.input.radius{radius.control}component.input.font-size{type.body.font-size}component.input.disabled.background{color.disabled.surface}component.input.disabled.border{color.disabled.border}component.input.disabled.text{color.disabled.text}component.control.checked{color.action.primary.@}component.control.track{color.border.strong}component.control.thumb{color.surface.default}component.control.radius{radius.badge}component.badge.radius{radius.badge}component.badge.padding-x{space.gap.tight}component.badge.font-size{type.caption.font-size}component.badge.neutral.background{color.surface.sunken}component.badge.neutral.label{color.text.secondary}component.badge.success.background{color.status.success.subtle}component.badge.success.label{color.status.success.@}component.badge.warning.background{color.status.warning.subtle}component.badge.warning.label{color.status.warning.@}component.badge.danger.background{color.status.danger.subtle}component.badge.danger.label{color.status.danger.@}component.badge.info.background{color.status.info.subtle}component.badge.info.label{color.status.info.@}component.card.background{color.surface.default}component.card.border{color.border.default}component.card.radius{radius.container}component.card.padding{space.inset.container}component.card.shadow{elevation.card}component.table.header-background{color.surface.sunken}component.table.row-height{size.row}component.table.cell-padding-x{space.inset.cell-x}component.table.row-border{color.border.default}component.table.row-selected{color.surface.selected}component.table.font-size{type.data.font-size}component.tabs.indicator{color.action.primary.@}component.tabs.label.@{color.text.secondary}component.tabs.label.active{color.text.primary}component.overlay.background{color.surface.raised}component.overlay.radius{radius.container}component.overlay.shadow{elevation.overlay}component.overlay.scrim{color.surface.scrim}component.overlay.item-height{size.control.default}component.tooltip.background{color.surface.inverse}component.tooltip.label{color.text.inverse}component.transition.duration{motion.duration.feedback}component.transition.easing{motion.easing.standard}

Decisions reference primitives, so changing one primitive updates every decision and component that uses it.

Naming in Multi-brand: lowercase words in paths. Lowercase paths read the same everywhere. Components never change; brand primitives do.