question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[RFC] Use design tokens of Ant Design v5 to customize component

See original GitHub issue

Summary

As we all know that Ant Design v5 is using CSS-in-JS to generate style now, and a lot of tokens which is used for generating themes are also introduced in v5. We would provide hooks like useToken and useStyle for users to customize components with tokens and CSS-in-JS used in Ant Design.

Motivation

For users who want to use Ant Design to do more design, as well as third-party libraries based on Ant Design, directly using Ant Design’s CSS-in-JS solution and being able to use Design Token directly will allow them to follow Ant Design’s design system, getting a consistent experience with Ant Design.

Design Token is a wonderful design, we implemented a flexible theme system with Design Token. But this is not limited to Ant Design itself, users should also benefit from it, and integrate custom tokens to achieve more cool designs and themes.

Therefore Ant Design v5 will provide two complementary capabilities:

  1. Directly use Ant Design’s CSS-in-JS solution;
  2. Use and expand Ant Design’s Design Token to gain more flexible theme customization capabilities.

对于想用 Ant Design 做更多设计的用户,以及基于 Ant Design 的三方库来说,直接使用 Ant Design 的 CSS-in-JS 方案,并且能够直接使用 Design Token 能够让他们继续沿用 Ant Design 的设计系统,获得与 Ant Design 一致的体验。

Design Token 是一个绝妙的设计,我们利用 Design Token 实现了灵活的主题系统。但这并不会局限于 Ant Design 本身,用户也应该从中获利,融合自定义的 token 以实现更加炫酷的设计和主题。

因此 Ant Design v5 会提供两种相辅相成的能力:

  1. 直接使用 Ant Design 的 CSS-in-JS 方案;
  2. 使用并拓展 Ant Design 的 Design Token,获得更灵活的主题定制能力。

API

There are two hooks planed:

  • useCustomToken: used to inject custom tokens other than tokens provided by Ant Design.
  • useStyleRegister: used to generate styles with tokens and CSS-in-JS.

Basic Example

Use CSS-in-JS and token provided by Ant Design

const MyBtn = () => {
  useStyleRegister('MyBtn', (token) => ({ 
    '.my-btn': {
      color: token.colorPrimary,
    }
  }));

  return <button className="my-btn">My Button</button>;
}

Use customized token

Customized token can be injected in this way.

// Custom useToken
const useMyToken = () =>
  useCustomToken({
    seedToken: { colorSpecial: 'red' },
    formatToken: token => ({
      ...token,
      colorSpecialActive: 'purple',
    }),
  });
// Custom useStyleRegister
const useMyStyle = (componentName: string, styleFn: (token) => CSSObject) => {
  const token = useMyToken();
  return useStyleRegister(componentName, token, styleFn);
}
// And use it in your component
const MyBtn = () => {
  useMyStyle('MyBtn', (token) => ({ 
    '.my-btn': {
      color: token.colorSpecial,
    }
  }));

  return <button className="my-btn">My Button</button>;
}

Detailed Design

At the beginning, a solution with a higher degree of encapsulation was envisaged. The above APIs were curried, and allow users to divide into four steps when they want to expand the Design Token:

  1. Write useMyToken based on useCustomToken;
  2. Register useMyToken to the registerToken method and return a genStyleHook method;
  3. Use genStyleHook, pass in token-based styleFn, write CSS-in-JS, and return useStyle hook;
  4. Use the useStyle hook in component.

The features of this solution:

  • High degree of encapsulation, except for one-time configuration code, what users actually need to put into use is the genStyleHook method;
  • The parameter list is concise;
  • The configuration process is more complicated and the learning cost is high;
  • Requires writing configuration code outside of the React lifecycle.

In order to remain the flexibility of CSS-in-JS and Design Token, the solution described above was finally decided, the registerToken layer of encapsulation was removed, and the user’s usage steps were simplified as follows:

  1. Write useMyToken based on useCustomToken;
  2. Write useMyStyle based on useStyleRegister;
  3. Use useMyStyle in the component.

If you want to directly use the Design Token preset by Ant Design, the first two steps can be omitted. Of course, users can also curry useMyStyle by themselves to reduce the burden on components.


一开始设想过封装度更高的方案,将上述这些 API 柯里化,让用户想要拓展 Design Token 时分为四步:

  1. 基于 useCustomToken 编写 useMyToken;
  2. useMyToken 注册到 registerToken 方法中,返回一个 genStyleHook 方法;
  3. 使用 genStyleHook,传入基于 token 的 styleFn,编写 CSS-in-JS,返回 useStyle hook;
  4. 在组件中使用 useStyle hook。

这个方案的特点是:

  • 封装度高,除去一次性的配置代码,用户实际上需要大量投入使用的就是 genStyleHook 方法;
  • 参数列表简洁;
  • 配置流程比较复杂,学习成本较高;
  • 需要在 React 生命周期外写配置代码。

为了保持 CSS-in-JS 和 Design Token 的灵活度,最终还是决定了上文中所述的方案,去掉了 registerToken 这一层封装,将用户的使用步骤简化为:

  1. 基于 useCustomToken 编写 useMyToken;
  2. 基于 useStyleRegister 编写 useMyStyle;
  3. 在组件中使用 useMyStyle.

如果想要直接使用 Ant Design 预设的 Design Token,则前两步可以省略。当然用户也可以自行将 useMyStyle 柯里化,给组件减负。

Drawbacks

No obvious drawbacks yet.

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:7 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
afc163commented, Jun 16, 2022

专门搞个板块放 rfcs 如何?https://github.com/ant-design/ant-design/discussions

0reactions
arvinxxcommented, Jun 16, 2022

核心要解 v4升v5 的方案吧。我之前 YY 过几种方案:

基础:原有的 V4 CSS Modules

大部分业务都会这么去用

// style.less
@import '~antd/es/style/themes/default';

.list {
 border: 1px solid @primary-color;
 border-radius: 2px;
 box-shadow: 0 8px 20px @shadow-color;
}

// index.tsx
import styles from './style.less';


const App = ({list}) => {
  return (
    <List
      dataSource={list}
      className={styles.list}
    />
  );
};

1. V5 CSS Modules

此方案不改动原来的任何样式结构,只是将 v4 的 less变量,改为v5的 token(用css variable 的模式)

.list {
  border: 1px solid var(--colorPrimary);
  border-radius: 2px;
  box-shadow: 0 8px 20px var(--colorShadow);
}

// index.tsx
import styles from './style.less';


const App = ({list}) => {
  return (
    <List
      dataSource={list}
      className={styles.list}
    />
  );
};

2. V5 CSS IN JS 对象模式

这种JS对象的模式应该是现在 antd 内部组件库的使用方式。但我觉得业务里不会想这么去写的。有点别扭

// style.ts
import { createStyles } from '@ant-design/styles';

export default createStyles((token) => ({
  list:{
    border: `1px solid ${token.colorPrimary}`,
    borderRadius: 2,
    boxShadow: `0 8px 20px ${token.colorShadow}`,
  }
})
// index.tsx
import styles from './style';


const App = ({list}) => {
  return (
    <List
      dataSource={list}
      className={styles.list}
    />
  );
};

3. V5 CSS IN JS 字符串模式

这是个人最期望的模式。基本上不会太改变原有的写法。

// style.ts
import { createStyles } from '@ant-design/styles';


export default createStyles((token) =>`
.list {
 border: 1px solid  ${token.colorPrimary};
 border-radius: 2px;
 box-shadow: 0 8px 20px ${token.colorShadow}`;
}
`
// index.tsx
import styles from './style';

const App = ({list}) => {
 const styles =  createStyles()
  return (
    <List
      dataSource={list}
      className={styles.list}
    />
  );
};

4. V5 CSS in JS(纯消费 Token 的方案)

这个是 期贤 说他在自己实践的方案。只要antd 给 token 就好了,从灵活性上来说是不错的。但旧业务升级新业务,采用这种方式要全部重构,成本会非常高。

import { css } from '@emotion/css';
import { useToken } from 'antd';

const buttonStyle = (token)=>css`
    border: 1px solid  ${token.colorPrimary};
    border-radius: 2px;
    box-shadow: 0 8px 20px ${token.colorShadow}`;
  `;

const App: FC = ({list}) => {
  const token = useToken();
  return (
    <List
      className={buttonStyle(token)}
      dataSource={list}
    />
  );
};

简单评估了下,供参考:

V5 CSS Modules V5 CSS in JS(对象模式) V5 CSS in JS(字符串模式) V5 CSS in JS(纯 token )
升级成本
熟悉度

最推荐的方案确定以后,antd token 在设计侧的消费模式才能确定下来。(即在 kitchen 里提供给开发 token 的代码模式)

Read more comments on GitHub >

github_iconTop Results From Across the Web

Customize Theme - Ant Design
Ant Design allows you to customize our design tokens to satisfy UI diversity from business or brand requirements, including primary color, border radius, ......
Read more >
About Design token in Design system | by Kim Dinh Son
The designer will define the class to use for the object with specific explanations of what it is (Component-specific), uniformly what the alias ......
Read more >
Choosing the right component library for your design system
Can I ask a question? Would you use mantine and sass together? Is sass just an addition to css, not really it's own...
Read more >
Customize the Ant Design Select Component - Level Up Coding
I recently answered a question on Stack Overflow where a user was trying to customize the layout/style of their Ant Design Select component....
Read more >
Components - Ant Design System for Figma
Open the Figma Tokens plugin. · Open the light / seed set tab. · Find and right-click on the borderRadius token in the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found