Efficient Style Management: Design Token Architecture and Naming with the CTI Methodology
Design tokens are a fundamental element of modern design systems, ensuring seamless collaboration between designers and developers. They enable the standardization of visual product attributes like colors, fonts, and spacing, transforming raw values into named variables. A well-designed token system significantly accelerates new interface development, simplifies scaling and customization, and minimizes technical debt by eliminating the need to manually change hardcoded style values across disparate components. In this article, we will delve into the architecture of design tokens and the specifics of naming conventions using the popular CTI methodology, which underpins many advanced design systems.
Multi-Level Abstraction of Design Tokens
For building a flexible and scalable design system, the approach to value abstraction is critical. Modern systems utilize a three-layer model (Primitive → Semantic → Component), often augmented with a zero layer—raw data—for completeness. This model ensures a structured data flow, where changes at lower levels automatically propagate to higher ones, guaranteeing consistency and simplifying global style updates.
0. Raw Values: These are basic, unabstracted data, such as hexadecimal color codes (#0055FF), pixel size values (16px), or specific font names ('Inter', sans-serif). They serve as the starting point but should not be used directly in code or designs to avoid technical debt.
1. Primitive Tokens: This is the first level of abstraction. Primitive tokens digitize raw data, giving them meaningful yet still abstract names. For instance, #0055FF might become blue-500. If a brand decides to change the shade of its corporate blue, updating the blue-500 value in one place is sufficient, and this change will automatically apply to all dependent tokens. Primitive tokens often describe color palettes, spacing scales, or font sizes.
2. Semantic Tokens: These tokens describe the role or purpose of a resource within the interface, answering the question 'Why?'. They link primitive tokens to specific usage contexts. For example, blue-500 could be used to create color-bg-primary (the primary background color). Semantic tokens play a crucial role in implementing themes (light/dark) and adapting to different modes, as the same semantic token can reference different primitives depending on the active theme.
3. Component Tokens: This level describes the specific application of a style within an individual element or component, answering the question 'Where?'. Component tokens allow for granular style adjustments for specific components without affecting other elements that might use the same semantic tokens. They serve to manage exceptions and specific component requirements while ensuring the inheritance of general semantics. For instance, color-button-bg-primary-hover might be unique to a button, even if its base semantic token is used elsewhere.
The CTI Methodology: Naming Architecture
CTI (Category → Type → Item) is one of the most popular naming models for design tokens, particularly widely used in conjunction with the Style Dictionary tool, which popularized this approach. The core idea behind CTI is that a token's name prioritizes its physical property or category rather than the component it belongs to. This makes the system easily interpretable for compilers and scripts.
The naming formula in CTI typically looks like this: Category-Type-Item-Subitem-State.
Let's break down each element:
- Category: Defines the basic physical nature of the token. This is always the first word in the token's name and indicates the data type. Examples:
color,size,font,spacing,radius. - Type: Describes which UI property this category applies to. Examples:
background,text,border,icon. - Item: Specifies the particular interface element or component the token relates to. Examples:
button,dropdown,container. - Sub-item (Modifier): Adds clarification to the item, indicating its variant or role. Examples:
primary,secondary,success,warning,danger. - State: Describes the interactive state of an element. Examples:
hover,active,disabled,focus.
For example, a token for the background color of a primary button in an active state would look like color-background-button-primary-active.
Advantages and Disadvantages of the CTI Approach
Like any methodology, CTI has its strengths and weaknesses, which are important to consider when designing a design system.
Advantages of CTI:
- Optimization for Compilers: Since the first word of a token always indicates its category (
color,size,font), it's extremely easy for compiler scripts (e.g., Style Dictionary) to understand what data they are working with. This simplifies the automatic generation of CSS variables, SCSS mixins, Swift files, and other formats from JSON token definitions, minimizing the need for custom configurations. - Efficient Auditing and Global Changes: For a frontend developer wanting to check or modify all spacing in an application, simply searching for the prefix
$spacing-or--spacing-is sufficient. This quickly provides a complete list of all spacing variables, which is convenient for global audits or bulk changes. - Standardization: CTI is the default architecture for tools like Style Dictionary, making it well-documented and understandable for many developers who have worked with design systems.
Disadvantages of CTI:
- Component Style Dispersion: In modern component-oriented frameworks (React, Vue), a component, such as a button, is an isolated entity. With the CTI approach, the styles for this button are scattered throughout the design system: color might reside in
colors.json, spacing inspacings.json, and radii inradii.json. To assemble or remove a component, a developer has to "jump around" different files, which breaks context and complicates the workflow. - Search and Autocomplete Difficulty: For a developer styling a button, it's often more important to quickly find everything related to
buttonandprimary, rather thancolororbackgroundprefixes. In long CTI tokens, these keywords appear in the middle. Autocomplete in an IDE initially suggests many colors, requiring the developer to type a significant portion of the token to reach the desired component. - Component Refactoring Effort: If the business decides to rename a component (e.g.,
modaltodialog), with the CTI approach, a frontend developer would have to search for and rename tokens across numerous categories (colors, shadows, z-index, spacing). If the component were prioritized (dialog-bg-color), renaming a single folder or group of tokens would suffice.
Semantic vs. Component Tokens: Delineating Roles
Understanding the distinctions between semantic and component tokens is key to building a flexible design system. Although their naming formulas are similar, their purposes differ fundamentally.
Semantic tokens answer the question 'Why?'. They define the role or intent of a style. For example, color-bg-primary means "primary background color," regardless of where it's used. These tokens are highly reusable and serve to ensure overall consistency and theme support. Their naming formula is: [category]-[property]-[role]-[prominence]-[state].
Component tokens answer the question 'Where?'. They describe styles specific to a particular component. They are used when it's necessary to deviate from general semantics or apply a unique style to a specific element without affecting other parts of the system. Essentially, they are managed exceptions. Their naming formula is: [category]-[component]-[property]-[role]-[prominence]-[state]. As you can see, [component] is simply added to the chain.
Golden Rule: If a token is reused in different places and defines a general purpose, it is a semantic token. If a style needs to be changed for only one specific element or component, it is a component token.
Detailing CTI Naming Elements
For a deeper understanding of CTI naming, let's examine each of its elements in more detail with examples:
- Category: The main folder or data type. This forms the basis for organizing tokens.
* color – for all color values.
* spacing – for internal and external spacing.
* radius – for corner radii.
* shadow – for shadow parameters.
* typography – for text styles (size, weight, line height).
* size – for element width/height.
* z-index – for managing element layering order.
* opacity – for opacity values.
* duration – for animation durations.
- Property: Clarifies which part of the UI the token relates to within its category.
* bg / surface – for background color.
* text – for text color.
* border – for border color.
* icon – for icon color.
* outline / ring – for focus outlines.
* overlay – for modal backdrop color.
- Role (Meaning / Purpose): Defines the functional or emotional significance of the token.
* primary / secondary / tertiary – for hierarchy indication.
* brand / accent – for brand colors.
* success – for success messages (green).
* warning – for warnings (yellow).
* danger / error – for errors (red).
* neutral – for neutral elements (gray).
* inverse – for elements that invert color on dark backgrounds.
* static – for colors that do not change with themes (white/black).
- Prominence (Hierarchy / Intensity): Describes the intensity or visibility of an element.
* default / main / base – a reference point, base state (often omitted in the name).
* muted – less prominent.
* subtle – very subtle.
* intense – more pronounced.
* on-brand – for contrasting content over a brand background.
- State / Modifier / Size: Additional refinements.
* States: hover, active, focus, disabled – for interactive states.
* Sizes: sm, md, lg, xl – for various component or element sizes.
Important Rule for the default State: If a token is in its base, quiescent state, the -default suffix is usually omitted. For example, color-text-primary implicitly refers to the default state. Other states are added after the role, such as color-text-primary-hover.
Practical Examples of CTI Token Structure
To solidify understanding, let's look at a few practical examples of building tokens for buttons, demonstrating the transition from raw values to specific component tokens.
Example 1: accent Button in default State
Let's assume we have a primary button with an accent color.
- 0. Raw Value:
#0055FF(raw blue color) - 1. Primitive Token:
blue-500(abstraction of the raw value) - 2. Semantic Token:
color-bg-accent(primary accent background color, referencesblue-500) - 3. Component Token:
color-button-accent-bg(accent button background color, referencescolor-bg-accent)
Here, we see how we transition from a general value (blue-500) to a more specific one (color-button-accent-bg). It's important that in the component token, we don't write -default, as it's implied.
Example 2: accent Button in hover State
Now, let's consider how the naming changes for the same button on hover.
- 0. Raw Value:
#0044DD(darker blue) - 1. Primitive Token:
blue-600(abstraction of the darker blue) - 2. Semantic Token:
color-bg-accent-hover(accent background color on hover, referencesblue-600) - 3. Component Token:
color-button-accent-bg-hover(accent button background color on hover, referencescolor-bg-accent-hover)
Here, the -hover suffix is explicitly added, indicating an interactive state. Each level of abstraction makes the design system more flexible, allowing for shade changes at the primitive level without renaming thousands of tokens.
Example 3: secondary Button in default State
For a secondary button, a different palette might be used, for instance, with transparency.
- 0. Raw Value:
#0055FFwith 10% transparency orrgba(0, 85, 255, 0.1) - 1. Primitive Token:
blue-transparent-100 - 2. Semantic Token:
color-bg-secondary(referencesblue-transparent-100) - 3. Component Token:
color-button-secondary-bg(referencescolor-bg-secondary)
This approach allows for easy palette switching for different button types, utilizing a common token structure.
Example 4: secondary Button Text in default State
Let's consider a token for the text within a secondary button.
- 0. Raw Value:
#0055FF - 1. Primitive Token:
blue-500 - 2. Semantic Token:
color-text-on-brand(text color over a brand background, referencesblue-500). Here, theon-brandmodifier appears, indicating the usage context. - 3. Component Token:
color-button-secondary-text-on-brand(secondary button text color, referencescolor-text-on-brand)
As you can see, the category (color, spacing, typography) always comes first, followed by the property or component, and then modifiers and states. This "general to specific" principle ensures predictability and ease of navigation within the design system.
Key Takeaways
- Design tokens are a key element for creating scalable, consistent, and easily maintainable design systems, preventing technical debt associated with hardcoding styles.
- The multi-level abstraction model (Raw Values → Primitive → Semantic → Component Tokens) provides flexibility and manageability, allowing global changes from a single point.
- The CTI methodology (Category → Type → Item) is a popular naming approach that is convenient for automated processing by compilers but can complicate contextual search and component style refactoring.
- Semantic tokens define the role and purpose of a style, ensuring reusability and theme support, while component tokens serve for granular adjustments and managing exceptions within specific components.
- Clear naming rules using categories, properties, roles, hierarchies, and states are critically important for maintaining order and predictability within a design system.
— Editorial Team
No comments yet.