# Atlassian DESIGN.md
> A portable, token-first manifest for producing anything that should look like it belongs at
> Atlassian — product UI, slides, charts, dashboards, onboarding screens, or marketing surfaces.
Everything needed to build UI is in this file: **YAML above** (every color hex, type scale, spacing,
corner radii, border widths, and a few control "recipes") plus **this prose** (how the pieces fit
together). Rules use RFC 2119: MUST, MUST NOT, SHOULD, MAY.
For implementation-level references — per-component API bindings, dark/light token catalogs, prompt
guidance, and linting rules — load the Atlassian Design System MCP server or
**atlassian-design-system** skill.
### Table of contents
**Canonical (spec-shaped):** [Overview](#overview) · [Colors](#colors) · [Typography](#typography) ·
[Layout](#layout) · [Elevation & Depth](#elevation--depth) · [Shapes](#shapes) ·
[Components](#components) · [Do's and Don'ts](#dos-and-donts)
**Atlassian extensions:** [Icons](#icons) · [Motion](#motion) · [Voice and tone](#voice-and-tone) ·
[Accessibility](#accessibility) · [Responsive behaviour](#responsive-behaviour)
---
### Related
- [Atlassian Design System](https://atlassian.design) — canonical token catalog, component APIs, and
foundations.
- **atlassian-design-system** skill — progressive-disclosure skill for token/component lookup and
ADS MCP usage when you have an ADS-capable stack.
- ADS MCP tools — direct token, component, and linting integrations where available.
- ADS ESLint plugins (design system and UI styling standards) — enforcement layer for CI in repos
that wire them up.
- Full-length `DESIGN.md` — per-component API bindings, dark-anchor palettes, agent prompt guide,
and design-rigor checks.
---
## Overview
### About this file
> A portable, token-first manifest for producing anything that should look like it belongs at
> Atlassian — product UI, slides, charts, dashboards, onboarding screens, or marketing surfaces.
Everything needed to build UI is in this file: **YAML above** (every color hex, type scale, spacing,
corner radii, border widths, and a few control "recipes") plus **this prose** (how the pieces fit
together). Rules use RFC 2119: MUST, MUST NOT, SHOULD, MAY.
This file is for generating UI in the style of Atlassian's system, not for use generating production
screens inside Atlassian apps, and focuses on design principles and intention, rather than specific
implementation details. Use the Atlassian Design System MCP server, or the ADS `Skills.md` file, to
get detailed, token-efficient references for how to implement Atlassian UI using the ADS tokens and
component libraries, as well as information on coding standards.
This file is a succinct canonical standalone manifest. For deeper implementation detail, load the
Atlassian Design System MCP server or the `atlassian-design-system` skill.
The `DESIGN.md` spec is still in alpha, and this file diverges from the spec in a few areas:
- Some tokens have transparency, which is required in the ADS token system
- Some components reference properties beyond the set in the current standard to encapsulate more of
the behaviour of the component
### Table of contents
**Canonical (spec-shaped):** [Overview](#overview) · [Colors](#colors) · [Typography](#typography) ·
[Layout](#layout) · [Elevation & Depth](#elevation--depth) · [Shapes](#shapes) ·
[Components](#components) · [Do's and Don'ts](#dos-and-donts)
**Atlassian extensions:** [Icons](#icons) · [Motion](#motion) · [Voice and tone](#voice-and-tone) ·
[Accessibility](#accessibility) · [Responsive behaviour](#responsive-behaviour)
### Brand & Style
Atlassian product UI is **neutral-dominant with restrained saturation, built on an 8px rhythm, a
t-shirt radius scale, and a four-plane elevation model.** Surfaces are calm; color carries meaning;
depth is earned, not decorative. Where brand expression is needed, a single layer of Charlie
typography and logo artwork is applied over an otherwise product-native canvas.
#### Atmosphere rules
- **MUST** default to neutral backgrounds (`surface`, `background-neutral`) for the ~90% of the
canvas that is not communicating meaning.
- **MUST** reserve saturated color for one of: semantic roles (brand, danger, warning, success,
information, discovery), decorative accents (tags, file types, avatar chips), or data
visualization.
- **MUST** compose layouts on the 8px grid via the `spacing` scale (`space-100`, `space-200`, etc. —
see [Layout](#layout)).
- **MUST** pair every elevated surface with its matching shadow token (see
[Elevation & Depth](#elevation--depth)).
- **MUST NOT** imitate Material's depth theatre (floating cards everywhere), generic Shadcn/Tailwind
neutral gradients, or marketing site branding; this system is for practical product UI.
- **SHOULD** prefer whitespace and borders for grouping before reaching for elevation.
- **SHOULD** let the canvas be mostly quiet so that color and motion (when used) carry actual
signal.
#### Brand vs product
- **Atlassian Sans** is the product typeface for every screen, button, table, and form (see
[Typography](#typography)).
- **Charlie Display / Charlie Text** are reserved for marketing surfaces and hero moments — never
used in settings pages, dashboards, or dense product chrome.
- The **Atlassian wordmark and product lockups** belong on marketing surfaces, sign-in screens, and
email — never inline in product chrome as a decorative flourish. When a logo is needed in-product,
use the small monochrome glyph at icon-size, not the full wordmark.
#### Reference points
- **Aligned with:** IBM Carbon (token-first discipline), Linear (restraint), GitHub Primer (neutral
backbone with semantic accents).
- **Not aligned with:** Material Design (heavier elevation, broader saturation), Shadcn/Tailwind
defaults (greyscale gradients, generic radius), Fluent (heavier acrylic/blur effects).
---
## Colors
ADS has four kinds of color, and they are not interchangeable:
1. **Neutrals and surfaces** — backbone for 80–90% of the canvas.
2. **Semantic roles** — meaning carriers (brand, danger, warning, success, information, discovery).
3. **Accent ramps** — decoration only (tags, file types, avatar chips).
4. **Chart colors** — data visualization only.
Refer to tokens by their YAML key in prose and recipes; emit literal hex in HTML/CSS. Hex values
below reflect this build's theme.
### 1) Neutrals and surfaces
| Token | Hex | Use |
| ----------------------- | --------------------- | ------------------------------------------------------------------------------------- |
| `surface` | `#FFFFFF` | Page / card fill |
| `surface-sunken` | `#F8F8F8` | **Inside** a page: wells, columns, grouped panels — not the outermost page background |
| `surface-raised` | `#FFFFFF` | Movable card — pair with `shadow-raised` |
| `surface-overlay` | `#FFFFFF` | Modal, popover, toast shell — pair with `shadow-overlay` |
| `text` | `#292A2E` | All paragraph-style copy |
| `text-subtle` | `#505258` | Labels, metadata — **not** long prose |
| `text-subtlest` | `#6B6E76` | Placeholders, hints |
| `border` | `#0B120E24` | Hairline dividers (alpha) |
| `border-bold` | `#7D818A` | Stronger divider |
| `border-input` | `#8C8F97` | Field outline |
| `border-focused` | `#4688EC` | 2px focus ring color |
| `link` / `link-pressed` | `#1868DB` / `#1558BC` | Text links |
The four surface planes and their paired shadows are documented in
[Elevation & Depth](#elevation--depth).
### 2) Semantic roles — _they mean something to the user_
These answer: "What state or message is this?" Examples: **danger** (destructive action, error),
**warning** (caution), **success** (done), **information** (neutral notice), **discovery**
(new/beta), **brand** (primary company action).
- Names always use whole words: `background-danger-bold`, `text-success`, `icon-information`, etc.
- Each role has the same four anchors — substitute the role to get the token name: `text-<role>`,
`icon-<role>`, `border-<role>`, and the filled `background-<role>-bold`. Hex values live in the
YAML.
- **MUST** treat `success` as a **semantic role token family**, not the decorative `accent-green`
family. In this system, success appears as a lime colour, but should always be referenced using a
success token. `accent-green` as a success substitute is a drift bug.
- **MUST** pick the role that matches the user meaning (a delete confirmation is **danger**, not
**warning**).
- On **bold** filled backgrounds (`*-bold`), text is usually `text-inverse`. **Exception:**
`background-warning-bold` is light yellow, so readable text on it is `text-warning-inverse` /
`icon-warning-inverse` (dark — not white).
- For **inline messages** (tinted background + icon + title + body): use semantic **background** +
**icon-** role tokens, but keep **body copy** in neutral **`text`** or **`text-subtle`**. Do
**not** tint paragraphs blue on a blue information panel — that fails both design and contrast
intuition.
### 3) Accent ramps — _pure decoration, not status_
These are the **`background-accent-*`**, **`text-accent-*`**, **`icon-accent-*`**,
**`border-accent-*`** keys.
- **Ten hues:** `lime`, `red`, `orange`, `yellow`, `green`, `teal`, `blue`, `purple`, `magenta`,
`gray`.
- **Four lightness steps** on backgrounds (pale → strong): `subtlest` → `subtler` → `subtle` →
`bolder`.
- **Pairing rule:** on `subtlest` / `subtler` backgrounds, use `text-accent-<hue>` or
`text-accent-<hue>-bolder`. On `subtle` use `text-accent-<hue>-bolder`. On `bolder` treat it like
any other strong fill and use `text-inverse`. The leading icon, when there is one, uses
`icon-accent-<hue>`. Substitute the hue and the same shape works for every ramp.
- **MUST NOT** use accent ramps to fake semantics — `background-accent-red-*` is not a substitute
for `background-danger-*`. Accents are for tags, file-type chips, avatars, decorative labels — not
"error".
### 4) Chart colors — _only for data visualization_
Three patterns appear in `colors`:
1. **`chart-categorical-1` … `chart-categorical-8`** — Eight distinct hues for **up to eight
different data series** on one chart (bar segments, lines, pie slices). Use them **in order**
when you do not have a reason to remap: series 1 → token 1, etc. The hex per index is in the
YAML.
2. **`chart-<hue>-bold` / `chart-<hue>-bolder` / `chart-<hue>-boldest`** — For **one hue** you get
three steps (lighter → darker) to show value tiers or emphasis inside a single colour family.
Example for yellow: **`chart-yellow-bold`** `#B38600`, **`chart-yellow-bolder`** `#946F00`,
**`chart-yellow-boldest`** `#7F5F01`.
3. **Semantic chart tokens** — when a series should read as a status:
| Token | When to use |
| ---------------------------------------------- | ------------------------------------------- |
| `chart-brand` | Primary metric line |
| `chart-success` / `chart-success-bold` | Completed, on-track, positive status |
| `chart-warning` / `chart-warning-bold` | Risk status, medium priority |
| `chart-danger` / `chart-danger-bold` | Negative status, off-track, high priority |
| `chart-information` / `chart-information-bold` | Low priority, in-progress |
| `chart-discovery` / `chart-discovery-bold` | New / experimental |
| `chart-neutral` | "To do" status, untracked, neutral baseline |
**MUST** add non-color cues (patterns, labels, shapes) so charts still read for colorblind users, or
if printed in greyscale.
---
## Typography
### Families
- **Atlassian Sans** (`family-body` / `family-heading`) — product UI: every screen, button, form,
table, dashboard. Based on Inter
- **Atlassian Mono** (`family-code`) — code blocks, inline code, monospace numerics. Based on
Jetbrains Mono.
- **Charlie Display / Charlie Text** (`family-brand-heading` / `family-brand-body`) — **marketing
and brand surfaces only**. Never in product settings or dense chrome.
- **MUST NOT** introduce third-party fonts (Inter, Geist, SF Pro, Roboto). The system fallback stack
already covers platforms where Atlassian Sans is unavailable
### Heading scale
Use plain `<h1>`–`<h6>` (one H1 per page, never skip levels) with the size + weight pair from the
`typography:` YAML. Pick the size that fits the surface — never hand-author headings outside the
scale, and never make a heading lighter or heavier than the token.
### Body scale
- **`body`** — default for component text; the single most common typography choice in product UI.
- **`body-large`** — long-form content (blog, documentation bodies).
- **`body-small`** — fine print, helper text, lozenges/tags/badges, table column headers. Use
sparingly.
Rules:
- **MUST** render paragraphs, list items, descriptions, and any continuous prose in `text`. Using
`text-subtle` for body copy to "differentiate it from headings" is a drift pattern — size and
weight already provide the hierarchy.
- Reserve `text-subtle` for secondary metadata (field labels, captions, bylines, nav items) and
`text-subtlest` for placeholders and helper text.
### Weights
- `weight-regular` — default body.
- `weight-medium` — text beside icons (buttons, nav items) — the "safe" bold against icon strokes.
- `weight-bold` — rare emphasis (lozenges, headings).
- **MUST** set font weight via these tokens, not arbitrary numerics like `fontWeight: 700`.
### Case
- **MUST** use **sentence case** for every piece of user-visible text in product UI: titles,
headings, buttons, menu items, tab labels, tooltips, flag titles, empty-state headings, table
column headers, form labels — everything.
- **MUST** capitalize proper nouns (people, company names, product names: _Jira_, _Confluence_,
_Trello_, _Atlassian_).
- **MUST NOT** use Title Case ("Create Work Item") — correct to sentence case ("Create work item")
on sight. This is one of the most common mistakes LLMs create when generating Atlassian UI.
- **MUST NOT** use ALL CAPS or `letter-spacing`-stretched uppercase anywhere — including eyebrows,
lozenges, tags, badges, and table column headers. There are no exemptions.
- Atlassian does **not** use the "eyebrow" / "overline" pattern (small label above a heading). If a
categorical label is genuinely needed, use a lozenge (semantic) or tag (decorative) beside the
heading, or a byline under the heading.
### Translation
- **MUST** treat every user-visible string as translatable. Never hard-code English; never
concatenate sentence fragments — pluralisation, gender, and word order vary by locale.
- **MUST** leave room for translated strings to grow ~30% longer than the English source without
breaking layout or truncating mid-word. Headings, button labels, and table column headers are the
usual victims.
---
## Layout
Atlassian spacing is an **8px-base** system. Every distance on the canvas — padding, margin, gap,
inset — **MUST** land on a token step from the `spacing:` YAML scale. No off-grid `13px`,
`10px 14px`, or arbitrary `rem`.
### Picking a step
The scale runs from `space-0` through `space-1000`; the full rem/px values live in the YAML. As a
decision aid: tight component interiors land at `space-0`…`space-100`, roomier component interiors
at `space-150`…`space-300`, page-level layout at `space-400` and up. Negative steps mirror the
positive scale for overlap and bleed.
### Principles
- **MUST** express relationships via proximity — things that belong together sit closer
(small/medium gaps); unrelated things sit further apart (medium/large gaps).
- **MUST** use consistent spacing within repeating elements (list items, table rows, card grids).
Consistency creates the visual rhythm that makes scanning fast.
- **MUST** vary the step to express hierarchy — e.g. `space-100` / `space-150` between a label and
its field, `space-300` / `space-400` between unrelated blocks. The same `space-200` on every edge
flattens hierarchy.
- **SHOULD** use a larger step around more important blocks (bigger surrounding space = more
important).
- **MAY** make optical adjustments (±one step) when strict tokens produce a visual imbalance — but
the starting point is always a token, not a pixel measurement.
### Implementation
- Emit spacing in the rem value the chosen token resolves to. **MUST NOT** use off-rail pixel values
such as `gap: 13px` or `padding: 10px 14px` — round to the nearest token step.
- For multi-column page layouts, use a 12-column grid with `space-300` gutters and `space-400` page
padding. Compose with flex/grid on `space-*` rhythm rather than fixed widths.
---
## Elevation & Depth
Atlassian elevation is a **four-plane** system plus an overflow treatment. Each plane has a specific
purpose; raising or overlaying is an intentional choice, not decoration.
### The four planes
| Plane | Surface token | Shadow token | Use |
| ----------- | ----------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Default** | `surface` | — | The flat canvas. Cards and containers here use borders, not shadows. |
| **Raised** | `surface-raised` | `shadow-raised` | Movable cards (Trello, Jira board cards). At most one raised region per screen. |
| **Overlay** | `surface-overlay` | `shadow-overlay` | Modals, dialogs, dropdown menus, floating toolbars, flags, popovers, tooltips, spotlight. Overlays can stack on overlays. |
| **Sunken** | `surface-sunken` | — | Wells that group content (Kanban columns, background panels) **inside** a page whose canvas is already `surface`. Only on the default plane — never stack sunken on raised. |
### Page canvas
- **MUST** use `surface` (`#FFFFFF`) as the page / artifact background. This is the rule for every
standalone surface — product pages, reports, dashboards, embedded views, email, slides, exported
documents. `surface` _is_ the canvas.
- **MUST NOT** use `surface-sunken` as the page background to create contrast against cards. Sunken
is a **well inside** a page (Kanban columns, a filters rail, a conversation thread) — not the
outermost surface. "Grey page, white cards" is the common drift pattern; the Atlassian pattern is
"white page, bordered cards, optional sunken wells inside."
- To create visual separation between a card and its container without switching surface tokens, use
`border` + `space-200` / `space-300` padding, or raise the card to `surface-raised` +
`shadow-raised`. Do not darken the canvas.
### Pairing rules
- **MUST** pair every `surface-raised` with `shadow-raised`, and every `surface-overlay` with
`shadow-overlay`. Mixing shadows across planes is a bug; the shadow recipes live in the YAML so
callers never hand-author `box-shadow` values.
- **MUST** prefer the border-on-scroll treatment (`border` at the clip edge) as the default scroll
cue; reach for `shadow-overflow` only when borders would be missed (horizontal table scroll, modal
body scroll).
- **MUST** stack overlays along the planes — navigation under inline dialogs under popups under
modals under flags under tooltips. Don't invent new z-index buckets; reuse the existing plane that
matches your overlay's purpose.
---
## Shapes
### Corner radius
Atlassian uses a t-shirt radius scale, and each size maps to a class of component. **Choose radius
by _what the thing is_, not by taste.**
| Token | rem | px | Component class |
| ---------------- | -------- | ---- | ----------------------------------------------------------------------- |
| `radius-xsmall` | 0.125rem | 2px | Badges, checkboxes, avatar labels, keyboard shortcuts |
| `radius-small` | 0.25rem | 4px | Lozenges, tags, timestamps, tooltips, table thumbnails, compact buttons |
| `radius-medium` | 0.375rem | 6px | Buttons, inputs, selects, nav items, smart links |
| `radius-large` | 0.5rem | 8px | Cards, in-page containers, dropdown menus, floating UI |
| `radius-xlarge` | 0.75rem | 12px | Modal dialogs, Kanban columns, large containers, tables |
| `radius-xxlarge` | 1rem | 16px | Video players only |
| `radius-full` | (pill) | — | Avatars, pills, user-related UI, emoji reactions |
| `radius-tile` | 25% | — | Tile components only (icon tile, object tile) |
Rules:
- **MUST** select radius by the component class above. A button is `radius-medium`; a card is
`radius-large`; a modal is `radius-xlarge`.
- **MUST** use `radius-full` for circular avatars and pill-shaped elements.
- **MUST NOT** emit arbitrary radius values like `border-radius: 8px` or `10px`. Map to the nearest
token step.
- **MUST NOT** use `radius-tile` outside the tile component system.
### Focus ring
- **MUST** apply focus rings with `border-width-focused` (2px) and the `border-focused` color.
- **MUST** offset the ring 2px from the component's bounding box.
- **MUST** set the ring's own radius to the component's radius **+ 2px** (so a `radius-medium`
button gets a focus ring at `radius-large`).
- **MUST NOT** remove focus outlines without providing the same ring contract by hand (width, color,
radius + 2px).
### Borders
Border widths live on a three-step scale, distinct from spacing and radius. Stroke weight carries
meaning (resting vs selected vs focused) and never drifts into decoration.
| Token | rem | px | Use |
| ----------------------- | --------- | --- | ---------------------------------------------------------------------------- |
| `border-width-default` | 0.0625rem | 1px | Default hairline: input borders, card outlines, dividers, table row rules. |
| `border-width-selected` | 0.125rem | 2px | Selected state: the rail on an active tab/nav row, selected card outline. |
| `border-width-focused` | 0.125rem | 2px | Focus ring on every focusable control (see [Focus ring](#focus-ring) above). |
Rules:
- **MUST** use `border-width-default` (1px) for all resting borders. Anything thicker reads as
emphasis.
- **MUST** pair `border-width-selected` with the `border-selected` color (and the matching
text/background tokens) for selected state — never just thicken the resting border.
- **MUST NOT** use thick coloured `border-left` / `border-right` > 1px as the sole callout emphasis
— use a semantic surface + role icon instead (see [Components](#components) → SectionMessage).
- **MUST NOT** invent fractional widths (e.g. 1.5px) to land between steps. If no step fits, the
surface treatment is wrong, not the border.
---
## Components
The visual recipe (tokens, padding, radius, typography) for each foundational component is in the
YAML `components:` block at the top of this file — `button-default`, `button-primary`,
`icon-button`, `textfield-standard`, `section-message`, etc. This section covers the **behavioural**
and **layout** rules that YAML can't carry: which variants exist, when to use which, accessibility
contracts, and the anti-patterns to correct on sight.
Theme note: some products may opt into updated shape tokens (larger radii) via the platform shape
theme. Preserve component hierarchy, spacing rhythm, and emphasis order even when corner size
changes.
### Button
Primary inline action control. Use YAML-defined appearances and sizes only (`default`, `primary`,
`subtle`, `warning`, `danger`, `discovery`; default/compact, optional fit-container), and do not
invent additional appearances. Only use compact only in dense surfaces (tables, toolbars) — never as
a default.
- **States:** use YAML state mappings for hover/pressed/selected/disabled/loading; loading and
focus/invalid emphasis must not cause layout shift.
- **Icons:** leading/trailing icons inherit `currentColor`; do not hardcode icon colors.
- **Hierarchy note:** default button text is intentionally `text-subtle` (not `text`) so primary
actions keep stronger visual emphasis. Do not "correct" this to full-contrast text.
Rules:
- **MUST** use sentence case, imperative verbs (see [Voice and tone](#voice-and-tone)). "Create work
item", not "Submit" or "OK".
- **MUST NOT** use `primary` for more than one action per section. If you feel tempted to, one of
them is probably `default`.
- **MUST NOT** use `warning` or `danger` for CTAs that aren't warning or danger — an orange "Save"
button is a drift pattern.
- **MUST NOT** hand-author hover/pressed fills — every appearance has matching `*-hovered` /
`*-pressed` tokens.
- **SHOULD** reach for `subtle` (or a styled link) before inventing a "text-only" appearance.
### IconButton
Square or circular single-icon action for low-emphasis affordances (toolbars, row actions, inline
editors). Supports only `default`, `primary`, `discovery` and `subtle` appearances; it inherits
Button state/token behavior, including `currentColor` icon inheritance.
- **MUST NOT** use IconButton when the action's meaning isn't conveyed by an obvious glyph. Pair the
icon with a label if the affordance is non-obvious.
### TextField
Single-line text input wrapped by form message primitives (`form-label`, `form-helper-message`,
`form-error-message`, `form-valid-message`). Use YAML-defined appearances/states; use
`subtle`/`none` only when editability is still visually obvious.
- **Responsive density:** below `30rem`, use compact density; from `30rem` and up, use default
density (exact values in YAML).
- **Slots:** before/after slots are inline with no extra gap; interactive slot content must preserve
focus order.
Rules:
- **MUST** provide a visible label. Placeholder-as-label is banned; placeholders are not substitutes
for labels.
- **MUST** use the compact size only in dense surfaces (tables, inline filters) — never as a
default.
- **MUST NOT** render `subtle` or `none` without a visual affordance that the field is editable
(hover border, icon, or surrounding chrome).
- **MUST NOT** put interactive elements in the slot-before / slot-after unless you handle focus
order.
### SectionMessage
Inline page-level status/system notice. Semantic meaning is carried by role background + leading
icon; prose stays neutral. Use `section-message-<semantic-role>` pattern (canonical example:
`section-message-information`).
- **Anatomy:** icon, title, supporting text, optional 1-2 link-style actions.
- **Variant intent:** `information` = neutral context, `warning` = pre-action caution, `error` =
failure + next action, `success` = completion confirmation, `discovery` = new capability
announcement.
- **MUST** keep body copy in neutral `text` (not tinted role text). Tinting body text blue on a blue
information panel is the most common drift pattern; correct on sight.
- **MUST NOT** omit the icon. A SectionMessage without an icon reads as a plain coloured box and
loses its semantic affordance.
- **MUST NOT** use `error` for "user input didn't validate" — that belongs in `form-error-message`
beside the field. SectionMessage `error` is for page-level / request-level failures.
### Other components
These components are represented in YAML by token bindings; use this section for intent and usage:
- **Card** — single surface tile. Fill `surface`, hairline `border`, `radius-large`. Use
`surface-raised` + `shadow-raised` only when movable; otherwise prefer bordered default-surface
cards.
- **Popup** — transient overlay shell for menus/popovers/date pickers. Wrapper provides
`surface-overlay` + `shadow-overlay` + radius; padding belongs inside content, not wrapper chrome.
- **Tooltip** — inverted short-form helper label with default/truncate width modes (240px / 420px).
Keep it non-interactive and keyboard reachable.
- **Link** — default, subtle, and inverse modes are available. Use subtle sparingly; links should
still be discoverable.
- **Tabs** — 1px baseline plus selected underline marker (`border-width-selected`) aligned to label
inset, not outer hit target. Keep selected state on text + underline together.
- **Modal / Dialog** — centered overlay with blanket. Width tiers: 400 / 600 / 800 / 968px. Keep
header/body/footer as separate regions so padding and scroll behavior stay predictable.
- **Toggle** — 32×16 regular and 40×20 large tracks; `toggle.thumbTravel` should be animated as a
state transition, not jumped. Use success track only when checked. Show a tick/cross icon in the
track segment not covered by the thumb (tick on the "on" side, cross on the "off" side) so state
remains legible beyond color.
- **Radio / Checkbox** — 16px controls with 24px hit target. Preserve disabled, invalid, and
selected token states instead of custom fills. Checkboxes must show the check icon only in checked
state (and bar icon only for indeterminate); unchecked state has no check glyph.
- **Avatar / AvatarGroup** — circle by default; square uses per-size radii. Stacked groups overlap
with surface-colored ring separation; grid mode uses tokenized row/column gaps.
- **Spinner** — stroke-based loader with rotate + load-in motion. Preserve motion fields
`spinner.rotateDuration`, `spinner.rotateTimingFunction`, `spinner.loadInDuration`, and
`spinner.loadInTimingFunction` instead of bespoke curves.
- **Tag** — decorative classification only (categories, labels), not semantic status. Tags consist
of an accent-coloured border and icon, with a transparent background. `tag-gray` is the canonical
accent example; infer other accent variants via the same naming/token pattern (e.g.
`tag-<accent>`) rather than listing them exhaustively.
- **Lozenge** — semantic status. Lozenges must keep a visible border (`lozenge.borderWidth` +
role/base border color), not a fill-only pill. Preserve lightness-factor contrast behavior
(`lozenge.iconLightnessFactor`, `lozenge.borderLightnessFactor`) using CSS relative color syntax,
e.g. `oklch(from <base> calc(l * <factor>) c h)`. For static/non-computed output, keep a visible
1px semantic border using the matching `border-<role>` token rather than dropping the border.
`lozenge-success` is the canonical semantic example; infer other semantic appearances from the
same token-shape pattern.
- **Badge** — compact count primitive. `badge` (neutral) and `badge-success` are the canonical
examples; infer other semantic appearances from the same naming and token pattern instead of
listing every role.
- **Table** — headers are `body-small` + emphasized weight in `text-subtle`; rows/cells use `border`
separators and tokenized hover/selected states. Compact mode is for dense read-only views.
- **Code / Code block** — inline code uses compact neutral pill styling (`typography.code`); block
mode supports line numbers and highlighted rows.
- **Empty state** — sentence-case heading + explanatory body + explicit next-step CTA.
- **Charts** — map series to `chart-*` tokens and include non-color cues (pattern/shape/labels) for
grayscale and a11y.
---
## Do's and Don'ts
The scan-friendly TL;DR. Each line is a drift pattern to correct on sight. Tokens are referenced by
their YAML key; hex values resolve from the frontmatter.
| Do | Don't |
| ----------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| Hex anchored to a token (`text` → `#292A2E`) | Arbitrary one-off hex (`color: '#172B4D'`) with no token mapping |
| Padding / margin / gap on a `space-*` step | `padding: 13px` or any off-rail value |
| Corner radius from `radius-*` per the component class | `border-radius: 10px` not aligned to a token |
| Elevation via `shadow-overlay` / `shadow-raised` | Hand-authored `box-shadow` values |
| `surface-raised` paired with `shadow-raised` | Raised surface with no paired shadow |
| `background-danger-bold` for destructive CTAs | `background-accent-red-bolder` for destructive CTAs (accent ≠ semantic) |
| Success states via semantic `*-success-*` tokens (lime-leaning in this system) | `accent-green` tokens used as a stand-in for semantic success |
| Button per the [Components](#components) recipe | `<button>` with arbitrary inline hex |
| TextField per the [Components](#components) recipe | Raw `<input>` with arbitrary colours, or placeholder as label |
| Status as a Lozenge (semantic) | Decorative Tag used for status |
| Tag with transparent background + accent border/icon | Filled tag pills with semantic-looking backgrounds |
| Lozenge with a visible border | Fill-only lozenges with no border |
| Sentence case ("Create work item") | Title Case ("Create Work Item"); ALL CAPS / letter-spaced "EYEBROW" labels |
| Paragraphs and list items in `text` | Body copy in `text-subtle` to "differentiate it from headings" |
| SectionMessage: semantic background + neutral text + role icon | Blue prose on a blue information panel (tinted body text) |
| `surface` as the page canvas, cards on top with `border` | `surface-sunken` as the page background; sunken on info blocks / stat tiles / settings rows |
| Table cells in `body` (14px) | Cells shrunk to `body-small` / 12px / 13px for density |
| Atlassian core icon at 16px for chevrons, checks, arrows | Unicode / emoji / HTML-entity glyphs (`›` `→` `▶` `✓` `✕` `…` `⚠`) as icons |
| Full selected triad (`background-selected` + `border-selected` 2px + `text-selected`) | Only the selected border, only the background, or `border-brand` / `text-brand` standing in for selected |
| Imperative CTA ("Save", "Delete") | "Submit", "OK", "Click here" |
| Descriptive link text ("Learn about permissions") | "Learn more", "Click here" |
| Error: reason + action | Error: "Oops, something went wrong. Please try again." |
| Empty state with a next-step CTA | "No data" / "Nothing here yet" alone |
| Atlassian Sans in product; Charlie only on marketing | Inter / Geist / SF Pro / Roboto in product; Charlie in settings pages |
| Focus ring per [Shapes](#shapes) | `outline: none` with no replacement |
| Accessible name on every icon-only control (`aria-label`) | Icon-only buttons with no accessible name |
| `prefers-reduced-motion` respected | Auto-playing loops on dashboards |
| `chart-*` / semantic / accent ramps | Cyan–purple–neon decorative palettes not mappable to ADS tokens |
| Single card surface + `border` | Nested card-on-card or stacked floating shadows everywhere |
| `icon-subtle` / `icon-subtlest` for secondary indicators (chevrons, bullets, sort arrows) | `icon-brand` as the default "important" icon colour on every prominent icon |
| Semantic surface (`background-*-subtle`) + `border-*` for callouts and alerts | `border-left` / `border-right` > 1px in a saturated color as the sole callout emphasis |
| Solid `text-*` tokens + `weight-*` for hierarchy | Gradient-filled text (`background-clip: text` + `linear-gradient`) |
| Restrained metrics: `metric-*` surface per [Components](#components), no decoration | Default "hero metric" template (oversized number + tiny label + stat row + decorative gradient) |
| Varied layout, density, and sectioning on the `space-*` rhythm | Repeated identical tiles (icon + heading + body + CTA × N) as the only layout |
| Borders and whitespace for depth; `backdrop-filter` only when ADS specifies it | Glass cards, glow borders, or `backdrop-filter` blur stacks as generic polish |
| Charts with a labeled metric or legend (see [Components](#components) → Charts) | Tiny sparklines or mini-charts with no labeled metric or legend |
---
## Icons
- **Glyph style:** ~1.5px effective stroke, rounded outside corners, tight geometry — never mix icon
packs.
- **Sizes:** default **16×16** in product UI. For prominent contexts, place a 16px glyph inside a
larger square tile (`background-neutral` + `icon-accent-*`) rather than scaling the glyph itself.
- **Color:** set CSS `color` on a wrapper to an `icon-*` token; paths use `fill="currentcolor"`.
Pair `icon-subtle` with `text-subtle`, `icon-danger` with `text-danger`, and so on — the role of
the icon should match the role of the text it sits beside.
- **Accessibility:** meaningful icons carry an accessible name; decorative icons that sit beside a
label are hidden from assistive tech.
The full SVG catalog lives in `@atlaskit/icon` (and a partial one in the long-form `DESIGN.md`). Use
those as the source — never substitute Unicode arrows, emoji, or HTML-entity glyphs (`›` `→` `▶` `✓`
`✕` `…` `⚠`) for real icons.
---
## Motion
Motion clarifies _what changed, why it changed, and what to do next_ — it is a clarifying layer over
the UI, never decoration. Four principles guide every animation:
- **Human** — organic, subtle, rhythmic. Experiences should feel warm and alive rather than
mechanical.
- **Clarity** — motion is applied consistently to guide attention; if removing it doesn't cost the
user information or context, don't add it.
- **Accessible** — comprehension without discomfort. Reduced-motion preferences disable motion
entirely; the interface must remain fully usable with all motion off.
- **Performant** — motion reinforces speed and momentum. It should never add friction.
Every motion event is defined by three attributes — **duration**, **easing curve**, **property**
(`scale`, `fade`, `slide`, `color`). Pair them by intent:
- **Interactions (50–150ms)** — hover, press, list-item state changes. Keep near-instant for
high-frequency moves.
- **Transitions (150–400ms)** — elements entering, exiting, or repositioning (Modal, Panel, Flag,
Popup). Larger elements need longer durations to feel proportional. Make exit motion faster than
entrance so dismissed elements don't block the next step.
- **Easing.** `ease-out` for entrances, `ease-in` for exits, `ease-in-out` for two-way transitions
or scaling overlays. Save the "bold" curves (`motion.easing.ease-out-bold`,
`motion.easing.ease-in-out-bold`) for prominent moves like a Modal entering; use the "practical"
curves (`motion.easing.ease-out-practical`, `motion.easing.ease-in-practical`) for everyday hover
fades and Popup entrances.
- **One focal point.** When multiple elements need to animate, simplify so a single event leads and
the rest support it.
- **Brand moments only get richer motion.** Save expressive, characterful motion for low-frequency
moments (onboarding, first-run, milestone celebrations). Everyday UI motion stays efficient and
quiet.
### Rules
- **MUST** respect `prefers-reduced-motion: reduce` — disable non-essential transitions and replace
motion with instant state changes.
- **MUST** use durations from `motion.duration.*` and easings from `motion.easing.*` rather than
hand-authored values.
- **SHOULD** animate `transform` and `opacity` rather than `top` / `left` / `width` / `height` to
keep frames cheap.
- **MUST NOT** use bounce or elastic easing in product UI — those belong on marketing surfaces only.
- **MUST NOT** auto-play decorative loops on dense dashboards. Motion communicates change; idle
motion is noise.
- **MUST NOT** flash, rapidly oscillate, or sweep large areas of the screen.
---
## Voice and tone
Atlassian product voice is **active, short, plain, and human** — explain what's happening and what
the user can do.
- **MUST** use active voice and present tense. "Create work item" beats "A work item will be
created."
- **MUST** use imperative verbs on buttons and calls to action ("Save", "Delete", "Connect"). Never
"Submit", "OK", or "Click here".
- **MUST** structure errors as **reason + fix**. "We can't reach the server. Check your connection
and try again" — never "Oops, something went wrong. Please try again."
- **MUST** use descriptive link text ("Learn about permissions", never "Learn more" or "Click
here").
- **MUST** keep sentence case throughout (see [Typography](#typography)) — including buttons,
headings, and lozenge labels.
- **SHOULD** keep sentences short (~15 words) and prefer plain words over jargon. If a security or
legal term is required, define it on first use.
- **MUST** write inclusively — gender-neutral pronouns by default; no idioms that don't translate
("piece of cake", "shoot from the hip"); no metaphors that exclude (sports, military, regional
culture).
- **MUST NOT** apologise on the user's behalf ("we're sorry", "unfortunately") unless the system
genuinely caused the problem and the apology is brief.
- **MUST NOT** be playful in moments of friction (errors, destructive confirmations, billing). Save
warmth for empty states and success moments.
---
## Accessibility
WCAG 2.2 AA is the floor, not the ceiling, for accessibility in an Atlassian application.
- **S**emantic and neutral tokens already satisfy WCAG AA contrast; **MUST NOT** override token text
colours with off-token hex.
- **MUST** show a visible focus ring per [Shapes](#shapes) on every focusable element, using
`color-border-focused` and a 1px gap
- **MUST** accompany form inputs with a visible label, not a placeholder
- **MUST NOT** rely on colour alone to convey meaning. Pair status colour with an icon, label, or
shape (see [Components](#components) → SectionMessage and Charts).
- **MUST** support 200% zoom and 320px width without loss of content or function.
- **MUST** treat all user-visible strings as translatable. Do not hard-code English; never
concatenate sentence fragments — pluralisation and word order vary by locale. Account for
translated strings being longer than English source.
- **MUST** keep every interaction reachable by keyboard alone. Tab order follows visual order; no
keyboard traps; `Esc` dismisses overlays.
- **MUST** label every form input with a visible label, and associate validation messaging with
fields
- **MUST** label every icon-only control; decorative icons should be hidden (see [Icons](#icons)).
- **MUST** announce dynamic changes (toast/flag content, inline validation, async errors) to screen
readers via a `polite` region, and use `assertive` only for genuinely urgent failures.
- **MUST** use semantic landmarks, and one `<h1>` per page; never skip heading levels.
---
## Responsive behaviour
- **MUST** size in `rem` for typography and `space-*` tokens for spacing — never fix typography or
layout in `px`.
- **MUST** reflow content as the viewport narrows; **MUST NOT** hide critical actions on small
screens. Collapse navigation into a menu, stack two-column layouts vertically, and let tables
scroll horizontally rather than truncate columns.
- **MUST** keep tap targets at least `space-400` (32px) on a side for touch contexts.
- **MUST** use logical CSS properties (inline/block) instead of physical (left/right/top/bottom) so
layouts mirror correctly in right-to-left locales (Arabic, Hebrew).
- **SHOULD** test at 320px width, 768px tablet, and 1280px desktop as the three reference
breakpoints; widen further only with explicit need.
---