Skip to content

[DRAFT] feat: add design token css variable bridge#9805

Open
Laffery wants to merge 1 commit into
NG-ZORRO:masterfrom
Laffery:agent/agent/5361b444
Open

[DRAFT] feat: add design token css variable bridge#9805
Laffery wants to merge 1 commit into
NG-ZORRO:masterfrom
Laffery:agent/agent/5361b444

Conversation

@Laffery

@Laffery Laffery commented May 23, 2026

Copy link
Copy Markdown
Collaborator

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • Application (the showcase website) / infrastructure changes
  • Other... Please describe:

What is the current behavior?

ng-zorro currently uses Less variables as the primary path for theme customization, while React antd v5 has moved to Token + CSS-in-JS. This PR establishes a bridge layer between Design Token and CSS Variables for Angular.

Issue Number: N/A

What is the new behavior?

This PR introduces a Design Token to CSS Variable bridge mechanism:

  1. Token Schema Definition (components/style/tokens/definitions.ts): Defines token schema for color, font, radius, spacing, shadow, motion, z-index and other dimensions.

  2. CSS Variables Generation (components/style/themes/token-css-variables.less): Generates CSS Variables like --ant-color-primary, --ant-color-text, --ant-border-radius etc.

  3. Less Variable Compatibility (components/style/themes/variable.less): Updated to reference CSS Variables, maintaining backward compatibility.

  4. Token Map Documentation (components/style/tokens/token-map.md): Documents the mapping between Less variables and tokens.

  5. Build Script (scripts/build/generate-design-tokens.ts): Script to generate design tokens.

This establishes an evolvable token alignment mechanism, allowing ng-zorro's Less variables, CSS Variables, and future Tailwind preset / runtime theme to consume the same token source.

Does this PR introduce a breaking change?

  • Yes
  • No

This PR maintains backward compatibility with existing Less-based theme customization.

Other information

CSS Variables prefix: --ant-* only. Tailwind integration is out of current phase scope.


Multica Issue: be4d0fb6-0c58-410b-bb9b-219f70bc17a6

@Laffery Laffery requested a review from vthinkxie as a code owner May 23, 2026 14:40
Copilot AI review requested due to automatic review settings May 23, 2026 14:40
@codecov

codecov Bot commented May 23, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.40%. Comparing base (f6c3aa6) to head (b2e2cd5).
⚠️ Report is 2 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #9805   +/-   ##
=======================================
  Coverage   91.40%   91.40%           
=======================================
  Files         577      577           
  Lines       23847    23847           
  Branches     4186     4186           
=======================================
  Hits        21797    21797           
  Misses       1522     1522           
  Partials      528      528           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces an initial “design token → CSS variable” bridge for NG-ZORRO’s styling system by defining a token schema, generating token-backed CSS variables, documenting the token/variable mapping, and updating parts of the variable theme to consume the new CSS variables.

Changes:

  • Added a token definition registry (definitions.ts) plus a generator script to emit token-css-variables.less and token-map.md.
  • Updated variable.less to import the generated token CSS variables and switched several component/theme Less variables (e.g. Button, Card, Tag, Alert) to var(--ant-*) sources.
  • Added documentation (components/style/tokens/README.md, token-map.md) and an npm script (generate:tokens) to run the generator.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
scripts/build/generate-design-tokens.ts New generator that renders token CSS variables + mapping docs from token definitions.
package.json Adds generate:tokens script to run the token generator via tsx.
components/style/tokens/token-map.md Generated markdown mapping table documenting token ↔ Less variable ↔ CSS variable.
components/style/tokens/README.md Docs describing token layers/stability and how to run the generator.
components/style/tokens/definitions.ts Source-of-truth token schema/values used by the generator.
components/style/themes/variable.less Imports generated token CSS vars and maps selected Less vars to token CSS variables.
components/style/themes/token-css-variables.less Generated Less that emits --ant-* CSS variables for defined tokens.
Comments suppressed due to low confidence (1)

components/style/themes/variable.less:79

  • token-css-variables.less generates token variables like --@{ant-prefix}-color-primary, but the core Less variables here (@primary-color, @success-color, @info-color, etc.) still read from the legacy CSS variables (--@{ant-prefix}-primary-color, --@{ant-prefix}-success-color, ...). As a result, overriding the documented token CSS variables (e.g. --ant-color-primary) will not affect the actual theme output. Please either align the token CSS variable names with the legacy ones (via cssVariable overrides in token definitions), or update the legacy variables/derivations so the legacy variables fall back to the token variables (without introducing cyclic var() references).
@import './token-css-variables';

// -------- Colors -----------
// >>> Primary
@primary-color: ~'var(--@{ant-prefix}-primary-color)';
@primary-color-hover: ~'var(--@{ant-prefix}-primary-color-hover)';
@primary-color-active: ~'var(--@{ant-prefix}-primary-color-active)';
@primary-color-outline: ~'var(--@{ant-prefix}-primary-color-outline)';

@card-padding-base-sm: (@card-padding-base / 2);
@card-actions-background: @component-background;
@card-padding-base: ~'var(--@{ant-prefix}-card-padding)';
@card-padding-base-sm: 12px;
layer: 'component',
stability: 'stable',
lessVariable: '@card-shadow',
lessValue: '0 1px 2px -2px rgb(0, 0, 0, 0.16), 0 3px 6px 0 rgb(0, 0, 0, 0.12), 0 5px 12px 4px rgb(0, 0, 0, 0.09)',
Comment on lines +594 to +607
path: 'button.shadow',
layer: 'component',
stability: 'stable',
lessVariable: '@btn-shadow',
lessValue: '0 2px 0 rgb(0, 0, 0, 0.015)',
description: 'Default Button shadow.'
},
{
path: 'button.primaryShadow',
layer: 'component',
stability: 'stable',
lessVariable: '@btn-primary-shadow',
lessValue: '0 2px 0 rgb(0, 0, 0, 0.045)',
description: 'Primary Button shadow.'
Comment on lines +82 to +85
--@{ant-prefix}-card-actions-bg: @component-background;
--@{ant-prefix}-card-radius: @border-radius-base;
--@{ant-prefix}-card-shadow: 0 1px 2px -2px rgb(0, 0, 0, 0.16), 0 3px 6px 0 rgb(0, 0, 0, 0.12), 0 5px 12px 4px rgb(0, 0, 0, 0.09);
--@{ant-prefix}-button-primary-bg: @primary-color;
Comment on lines +92 to +95
--@{ant-prefix}-button-border-radius: @border-radius-base;
--@{ant-prefix}-button-border-radius-sm: @border-radius-base;
--@{ant-prefix}-button-shadow: 0 2px 0 rgb(0, 0, 0, 0.015);
--@{ant-prefix}-button-primary-shadow: 0 2px 0 rgb(0, 0, 0, 0.045);
| `card.padding` | component | stable | `@card-padding-base` | `--ant-card-padding` | `24px` |
| `card.actionsBg` | component | stable | `@card-actions-background` | `--ant-card-actions-bg` | `@component-background` |
| `card.radius` | component | stable | `@card-radius` | `--ant-card-radius` | `@border-radius-base` |
| `card.shadow` | component | stable | `@card-shadow` | `--ant-card-shadow` | `0 1px 2px -2px rgb(0, 0, 0, 0.16), 0 3px 6px 0 rgb(0, 0, 0, 0.12), 0 5px 12px 4px rgb(0, 0, 0, 0.09)` |
Comment on lines +78 to +79
| `button.shadow` | component | stable | `@btn-shadow` | `--ant-button-shadow` | `0 2px 0 rgb(0, 0, 0, 0.015)` |
| `button.primaryShadow` | component | stable | `@btn-primary-shadow` | `--ant-button-primary-shadow` | `0 2px 0 rgb(0, 0, 0, 0.045)` |

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a structured design token system to NG-ZORRO, transitioning from static Less variables to dynamic CSS variables. It includes a new token definition schema in TypeScript, a generation script to produce Less theme files and documentation, and updates to the core variable.less to consume these tokens. Feedback from the reviewer highlights a regression in maintainability where a dynamic calculation for card padding was replaced by a hardcoded value, suggesting the use of CSS calc() instead. Additionally, several instances of hardcoded rgb() values with alpha channels were flagged for replacement with rgba() to ensure better compatibility with older tools and consistency with the existing codebase.

@card-padding-base-sm: (@card-padding-base / 2);
@card-actions-background: @component-background;
@card-padding-base: ~'var(--@{ant-prefix}-card-padding)';
@card-padding-base-sm: 12px;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Changing the dynamic calculation (@card-padding-base / 2) to a hardcoded 12px is a regression in maintainability. Since @card-padding-base is now mapped to a CSS variable, Less cannot perform arithmetic on it at compile time. You should use the CSS calc() function to maintain the relationship between base and small padding.

@card-padding-base-sm: ~'calc(@{card-padding-base} / 2)';

layer: 'component',
stability: 'stable',
lessVariable: '@card-shadow',
lessValue: '0 1px 2px -2px rgb(0, 0, 0, 0.16), 0 3px 6px 0 rgb(0, 0, 0, 0.12), 0 5px 12px 4px rgb(0, 0, 0, 0.09)',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The shadow values are hardcoded with rgb() and fixed alpha values. This makes them non-reactive to theme changes (e.g., if @black or a base shadow color is changed). It is better to use rgba() for better compatibility and consistency with the existing codebase, or ideally reference Less variables.

Suggested change
lessValue: '0 1px 2px -2px rgb(0, 0, 0, 0.16), 0 3px 6px 0 rgb(0, 0, 0, 0.12), 0 5px 12px 4px rgb(0, 0, 0, 0.09)',
lessValue: '0 1px 2px -2px rgba(0, 0, 0, 0.16), 0 3px 6px 0 rgba(0, 0, 0, 0.12), 0 5px 12px 4px rgba(0, 0, 0, 0.09)',

layer: 'component',
stability: 'stable',
lessVariable: '@btn-shadow',
lessValue: '0 2px 0 rgb(0, 0, 0, 0.015)',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using rgb() with four arguments is part of CSS Colors Level 4. For broader compatibility with older tools and consistency with the rest of the repository, rgba() is preferred for colors with alpha channels.

Suggested change
lessValue: '0 2px 0 rgb(0, 0, 0, 0.015)',
lessValue: '0 2px 0 rgba(0, 0, 0, 0.015)',

layer: 'component',
stability: 'stable',
lessVariable: '@btn-primary-shadow',
lessValue: '0 2px 0 rgb(0, 0, 0, 0.045)',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using rgb() with four arguments is part of CSS Colors Level 4. For broader compatibility with older tools and consistency with the rest of the repository, rgba() is preferred for colors with alpha channels.

Suggested change
lessValue: '0 2px 0 rgb(0, 0, 0, 0.045)',
lessValue: '0 2px 0 rgba(0, 0, 0, 0.045)',

@Laffery Laffery changed the title feat: add design token css variable bridge [DRAFT] feat: add design token css variable bridge May 23, 2026
@noah-zzz

noah-zzz commented Jun 2, 2026

Copy link
Copy Markdown

This function is very good. When can it be used?

@noah-zzz

noah-zzz commented Jun 2, 2026

Copy link
Copy Markdown

When will this function be put into use?

@noah-zzz

noah-zzz commented Jun 2, 2026

Copy link
Copy Markdown

Will the next version be updated?

@lppedd

lppedd commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

This should absolutely NOT be rushed out as it's a major change of direction.

@Laffery

Laffery commented Jun 2, 2026

Copy link
Copy Markdown
Collaborator Author

Will the next version be updated?

@noah-zzp No, it won't.

@Laffery

Laffery commented Jun 2, 2026

Copy link
Copy Markdown
Collaborator Author

This should absolutely NOT be rushed out as it's a major change of direction.

@lppedd Absolutely right, it's just a simple try

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants