Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 44 additions & 34 deletions docs/guides/layout-spacing.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,40 +7,42 @@ relevantForAI: true

# Layout Spacing

Our design system provides a set of spacing tokens for consistent layouts and components. Some tokens share values but should be used semantically. For instance, while both `tags` and `buttons` are 0.75rem, `buttons` should be used for spacing between buttons.
Our design system provides a set of spacing tokens for consistent layouts and components. The current tokens are organized into a general t-shirt scale plus a handful of semantic tokens. Some tokens share a value but carry different meaning — prefer the semantically correct token for the context (e.g. use `gap.buttons` for spacing between buttons).

The `margin` and `padding` props on InstUI components accept these tokens via **dot-path notation** (for example `margin="general.spaceMd"` or `padding="padding.card.lg"`), and support the familiar CSS-like 1–4 value shorthand.

## Tokens

| Key | Value | Value in pixels |
| ----------------- | -------- | --------------- |
| space0 | 0rem | 0px |
| space2 | 0.125rem | 2px |
| space4 | 0.25rem | 4px |
| space8 | 0.5rem | 8px |
| space12 | 0.75rem | 12px |
| space16 | 1rem | 16px |
| space24 | 1.5rem | 24px |
| space36 | 2.25rem | 36px |
| space48 | 3rem | 48px |
| space60 | 3.75rem | 60px |
| sections | 2.25rem | 36px |
| sectionElements | 1.5em | 24px |
| trayElements | 1.5em | 24px |
| modalElements | 1.5em | 24px |
| moduleElements | 1em | 16px |
| paddingCardLarge | 1.5rem | 24px |
| paddingCardMedium | 1rem | 16px |
| paddingCardSmall | 0.75rem | 12px |
| selects | 1rem | 16px |
| textAreas | 1rem | 16px |
| inputFields | 1rem | 16px |
| checkboxes | 1rem | 16px |
| radios | 1rem | 16px |
| toggles | 1rem | 16px |
| buttons | 0.75rem | 12px |
| tags | 0.75rem | 12px |
| statusIndicators | 0.75rem | 12px |
| dataPoints | 0.75rem | 12px |
### General scale

| Key | Value | Value in pixels |
| -------------------- | -------- | --------------- |
| general.spaceNone | 0rem | 0px |
| general.space2xs | 0.125rem | 2px |
| general.spaceXs | 0.25rem | 4px |
| general.spaceSm | 0.5rem | 8px |
| general.spaceMd | 0.75rem | 12px |
| general.spaceLg | 1rem | 16px |
| general.spaceXl | 1.5rem | 24px |
| general.space2xl | 2rem | 32px |

### Semantic tokens

| Key | Value | Value in pixels |
| ---------------------------------- | -------- | --------------- |
| gap.sections | 3rem | 48px |
| gap.buttons | 0.75rem | 12px |
| gap.cards.sm | 0.75rem | 12px |
| gap.cards.md | 1rem | 16px |
| gap.cards.lg | 1.5rem | 24px |
| gap.cards.nestedContainers.sm | 0.5rem | 8px |
| gap.cards.nestedContainers.md | 0.75rem | 12px |
| gap.cards.nestedContainers.lg | 1rem | 16px |
| gap.inputs.horizontal | 0.75rem | 12px |
| gap.inputs.vertical | 1rem | 16px |
| padding.card.sm | 0.5rem | 8px |
| padding.card.md | 0.75rem | 12px |
| padding.card.lg | 1rem | 16px |

## Applying Spacing

Expand All @@ -55,7 +57,7 @@ Most components in the library support a `margin` prop that works similarly to t
type: example
---
<div>
<Button margin="0 buttons 0 0">Button 1</Button>
<Button margin="0 general.spaceSm 0 0">Button 1</Button>
<Button>Button 2</Button>
</div>
```
Expand Down Expand Up @@ -92,6 +94,14 @@ import canvas from '@instructure/ui-themes'
</div>
```

## Legacy tokens
## Deprecated tokens

For compatibility reasons we still resolve two earlier generations of spacing tokens at runtime, but they should **not** be used when creating new layouts — prefer the current tokens above.

### Phased-out tokens

The flat `space0`–`space60` scale and the flat semantic tokens (`sections`, `buttons`, `paddingCardLarge`, `selects`, `tags`, etc.) were an interim set and have been superseded by the current general scale and dot-path semantic tokens.

### Legacy tokens

For compatibility reasons we still provide the legacy spacing tokens (`xxLarge`, `medium`, etc.) so old layouts don't break when updating InstUI but these tokens shouldn't be used when creating new layouts.
The original legacy keywords (`xxxSmall`, `small`, `medium`, `large`, `xxLarge`, etc.) remain so old layouts don't break when updating InstUI.
45 changes: 44 additions & 1 deletion packages/emotion/src/styleUtils/ThemeablePropValues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,18 @@ const ThemeablePropValues = {

// SPACING
type OldSpacingKeys = keyof typeof ThemeablePropValues.SPACING
/**
* @deprecated Era-1 (legacy) spacing keywords. Still resolved at runtime, but
* prefer the current `CurrentSpacingValues` dot-path tokens (e.g. `general.spaceMd`).
* See https://instructure.design/layout-spacing.
*/
type OldSpacingValues = (typeof ThemeablePropValues.SPACING)[OldSpacingKeys]
/**
* @deprecated Era-2 spacing tokens (the `space0`–`space60` and flat semantic set)
* have been phased out. Still resolved at runtime, but prefer the current
* `CurrentSpacingValues` dot-path tokens (e.g. `general.spaceMd`, `gap.cards.md`).
* See https://instructure.design/layout-spacing.
*/
type NewSpacingValues =
| 'space0'
| 'space2'
Expand Down Expand Up @@ -120,7 +131,38 @@ type NewSpacingValues =
| 'tags'
| 'statusIndicators'
| 'dataPoints'
type SpacingValues = OldSpacingValues | NewSpacingValues
/**
* Current (era-3) spacing tokens. Referenced via dot-path notation and resolved
* against the new theme's `sharedTokens.spacing` map (see
* `@instructure/ui-themes` `newThemeTokens`). These are the recommended values
* for the `margin`/`padding` props. See https://instructure.design/layout-spacing.
*/
type CurrentSpacingValues =
// general t-shirt scale
| 'general.spaceNone'
| 'general.space2xs'
| 'general.spaceXs'
| 'general.spaceSm'
| 'general.spaceMd'
| 'general.spaceLg'
| 'general.spaceXl'
| 'general.space2xl'
// semantic gap tokens
| 'gap.sections'
| 'gap.buttons'
| 'gap.cards.sm'
| 'gap.cards.md'
| 'gap.cards.lg'
| 'gap.cards.nestedContainers.sm'
| 'gap.cards.nestedContainers.md'
| 'gap.cards.nestedContainers.lg'
| 'gap.inputs.horizontal'
| 'gap.inputs.vertical'
// semantic padding tokens
| 'padding.card.sm'
| 'padding.card.md'
| 'padding.card.lg'
type SpacingValues = CurrentSpacingValues | OldSpacingValues | NewSpacingValues
// adding `(string & {})` allows to use any string while still allowing specific string values to be suggested by IDEs
type Spacing = SpacingValues | (string & {})

Expand Down Expand Up @@ -152,6 +194,7 @@ export default ThemeablePropValues
export { ThemeablePropValues }
export type {
SpacingValues,
CurrentSpacingValues,
Spacing,
Shadow,
Stacking,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,4 +239,70 @@ describe('calcSpacingFromShorthand', () => {
consoleWarnSpy.mockRestore()
})
})

// Era-3 (current) tokens are referenced via dot-path notation and resolved
// against the new theme's nested `sharedTokens.spacing` map. This block mirrors
// that shape to verify the real consumer syntax (e.g. `margin="general.spaceMd"`).
describe('era-3 (current) spacing tokens', () => {
const eraThreeMap = {
general: {
spaceNone: '0rem',
space2xs: '0.125rem',
spaceXs: '0.25rem',
spaceSm: '0.5rem',
spaceMd: '0.75rem',
spaceLg: '1rem',
spaceXl: '1.5rem',
space2xl: '2rem'
},
gap: {
sections: '3rem',
buttons: '0.75rem',
cards: {
sm: '0.75rem',
md: '1rem',
lg: '1.5rem',
nestedContainers: { sm: '0.5rem', md: '0.75rem', lg: '1rem' }
},
inputs: { horizontal: '0.75rem', vertical: '1rem' }
},
padding: {
card: { sm: '0.5rem', md: '0.75rem', lg: '1rem' }
}
}

it('resolves a general scale token', () => {
expect(calcSpacingFromShorthand('general.spaceMd', eraThreeMap)).toBe('0.75rem')
})

it('resolves general.spaceNone', () => {
expect(calcSpacingFromShorthand('general.spaceNone', eraThreeMap)).toBe('0rem')
})

it('resolves a deeply nested semantic gap token', () => {
expect(
calcSpacingFromShorthand('gap.cards.nestedContainers.md', eraThreeMap)
).toBe('0.75rem')
})

it('resolves a semantic padding token', () => {
expect(calcSpacingFromShorthand('padding.card.lg', eraThreeMap)).toBe('1rem')
})

it('handles CSS-like shorthand mixing the general scale with auto', () => {
const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})

expect(
calcSpacingFromShorthand('general.spaceLg auto general.spaceXl', eraThreeMap)
).toBe('1rem auto 1.5rem')

consoleWarnSpy.mockRestore()
})

it('mixes semantic gap and padding tokens', () => {
expect(
calcSpacingFromShorthand('gap.cards.sm padding.card.md', eraThreeMap)
).toBe('0.75rem 0.75rem')
})
})
})
6 changes: 3 additions & 3 deletions packages/ui-alerts/src/Alert/v2/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,9 @@ type AlertOwnProps = {
*/
timeout?: number
/**
* Valid values are `0`, `none`, `auto`, `xxx-small`, `xx-small`, `x-small`,
* `small`, `medium`, `large`, `x-large`, `xx-large`. Apply these values via
* familiar CSS-like shorthand. For example: `margin="small auto large"`.
* Valid values are `0`, `none`, `auto`, and Spacing token values,
* see https://instructure.design/layout-spacing. Apply these values via
* familiar CSS-like shorthand. For example, `margin="general.spaceMd auto"`.
*/
margin?: Spacing
/**
Expand Down
6 changes: 3 additions & 3 deletions packages/ui-badge/src/Badge/v2/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,9 @@ type BadgeOwnProps = {
*/
display?: 'inline-block' | 'block'
/**
* Valid values are `0`, `none`, `auto`, `xxx-small`, `xx-small`, `x-small`,
* `small`, `medium`, `large`, `x-large`, `xx-large`. Apply these values via
* familiar CSS-like shorthand. For example: `margin="small auto large"`.
* Valid values are `0`, `none`, `auto`, and Spacing token values,
* see https://instructure.design/layout-spacing. Apply these values via
* familiar CSS-like shorthand. For example, `margin="general.spaceMd auto"`.
*/
margin?: Spacing
/**
Expand Down
6 changes: 3 additions & 3 deletions packages/ui-billboard/src/Billboard/v2/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,9 @@ type BillboardOwnProps = {
*/
readOnly?: boolean
/**
* Valid values are `0`, `none`, `auto`, `xxx-small`, `xx-small`, `x-small`,
* `small`, `medium`, `large`, `x-large`, `xx-large`. Apply these values via
* familiar CSS-like shorthand. For example: `margin="small auto large"`.
* Valid values are `0`, `none`, `auto`, and Spacing token values,
* see https://instructure.design/layout-spacing. Apply these values via
* familiar CSS-like shorthand. For example, `margin="general.spaceMd auto"`.
*/
margin?: Spacing
}
Expand Down
6 changes: 3 additions & 3 deletions packages/ui-breadcrumb/src/Breadcrumb/v2/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ type BreadcrumbOwnProps = {
*/
size?: 'small' | 'medium' | 'large'
/**
* Valid values are `0`, `none`, `auto`, `xxx-small`, `xx-small`, `x-small`,
* `small`, `medium`, `large`, `x-large`, `xx-large`. Apply these values via
* familiar CSS-like shorthand. For example: `margin="small auto large"`.
* Valid values are `0`, `none`, `auto`, and Spacing token values,
* see https://instructure.design/layout-spacing. Apply these values via
* familiar CSS-like shorthand. For example, `margin="general.spaceMd auto"`.
*/
margin?: Spacing
}
Expand Down
6 changes: 3 additions & 3 deletions packages/ui-buttons/src/BaseButton/v2/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,9 @@ type BaseButtonOwnProps = {
isCondensed?: boolean

/**
* Valid values are `0`, `none`, `auto`, `xxx-small`, `xx-small`, `x-small`,
* `small`, `medium`, `large`, `x-large`, `xx-large`. Apply these values via
* familiar CSS-like shorthand. For example: `margin="small auto large"`.
* Valid values are `0`, `none`, `auto`, and Spacing token values,
* see https://instructure.design/layout-spacing. Apply these values via
* familiar CSS-like shorthand. For example, `margin="general.spaceMd auto"`.
*/
margin?: Spacing

Expand Down
6 changes: 3 additions & 3 deletions packages/ui-buttons/src/Button/v2/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,9 @@ type ButtonOwnProps = {
withBackground?: boolean

/**
* Valid values are `0`, `none`, `auto`, `xxx-small`, `xx-small`, `x-small`,
* `small`, `medium`, `large`, `x-large`, `xx-large`. Apply these values via
* familiar CSS-like shorthand. For example: `margin="small auto large"`.
* Valid values are `0`, `none`, `auto`, and Spacing token values,
* see https://instructure.design/layout-spacing. Apply these values via
* familiar CSS-like shorthand. For example, `margin="general.spaceMd auto"`.
*/
margin?: Spacing

Expand Down
6 changes: 3 additions & 3 deletions packages/ui-buttons/src/CloseButton/v2/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,9 @@ type CloseButtonOwnProps = {
) => void

/**
* Valid values are `0`, `none`, `auto`, `xxx-small`, `xx-small`, `x-small`,
* `small`, `medium`, `large`, `x-large`, `xx-large`. Apply these values via
* familiar CSS-like shorthand. For example: `margin="small auto large"`.
* Valid values are `0`, `none`, `auto`, and Spacing token values,
* see https://instructure.design/layout-spacing. Apply these values via
* familiar CSS-like shorthand. For example, `margin="general.spaceMd auto"`.
*/
margin?: Spacing

Expand Down
6 changes: 3 additions & 3 deletions packages/ui-buttons/src/CondensedButton/v2/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ type CondensedButtonOwnProps = {
color?: 'primary' | 'primary-inverse' | 'secondary'

/**
* Valid values are `0`, `none`, `auto`, `xxx-small`, `xx-small`, `x-small`,
* `small`, `medium`, `large`, `x-large`, `xx-large`. Apply these values via
* familiar CSS-like shorthand. For example: `margin="small auto large"`.
* Valid values are `0`, `none`, `auto`, and Spacing token values,
* see https://instructure.design/layout-spacing. Apply these values via
* familiar CSS-like shorthand. For example, `margin="general.spaceMd auto"`.
*/
margin?: Spacing

Expand Down
6 changes: 3 additions & 3 deletions packages/ui-buttons/src/IconButton/v2/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,9 @@ type IconButtonOwnProps = {
withBorder?: boolean

/**
* Valid values are `0`, `none`, `auto`, `xxx-small`, `xx-small`, `x-small`,
* `small`, `medium`, `large`, `x-large`, `xx-large`. Apply these values via
* familiar CSS-like shorthand. For example: `margin="small auto large"`.
* Valid values are `0`, `none`, `auto`, and Spacing token values,
* see https://instructure.design/layout-spacing. Apply these values via
* familiar CSS-like shorthand. For example, `margin="general.spaceMd auto"`.
*/
margin?: Spacing

Expand Down
6 changes: 3 additions & 3 deletions packages/ui-byline/src/Byline/v2/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ type BylineOwnProps = {
*/
alignContent?: 'top' | 'center'
/**
* Valid values are `0`, `none`, `auto`, `xxx-small`, `xx-small`, `x-small`,
* `small`, `medium`, `large`, `x-large`, `xx-large`. Apply these values via
* familiar CSS-like shorthand. For example: `margin="small auto large"`.
* Valid values are `0`, `none`, `auto`, and Spacing token values,
* see https://instructure.design/layout-spacing. Apply these values via
* familiar CSS-like shorthand. For example, `margin="general.spaceMd auto"`.
*/
margin?: Spacing
/*
Expand Down
6 changes: 3 additions & 3 deletions packages/ui-file-drop/src/FileDrop/v2/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,9 @@ type FileDropOwnProps = {
*/
minWidth?: string | number
/**
* Valid values are 0, none, auto, xxx-small, xx-small, x-small, small,
* medium, large, x-large, xx-large. Apply these values via familiar
* CSS-like shorthand. For example: margin="small auto large".
* Valid values are `0`, `none`, `auto`, and Spacing token values,
* see https://instructure.design/layout-spacing. Apply these values via
* familiar CSS-like shorthand. For example, `margin="general.spaceMd auto"`.
*/
margin?: Spacing
/**
Expand Down
Loading
Loading