DEV Community

Cover image for Using CSS variables with AntD Design system
Mikhail Petrov
Mikhail Petrov

Posted on • Originally published at Medium

Using CSS variables with AntD Design system

Ant Design offers a CSS-in-JS approach for styling your custom components. But how can developers use its Design System tokens in CSS or preprocessors (SASS, LESS)?

Let’s take a look at a small example with a set of panels with buttons in a row.

export const Test: React.FC = () => (
  <div className="app">
    {map(range(4), (index) => (
      <div
        key={index}
        className='container'
      >
        <Button type='primary'>
          Button {index}
        </Button>
      </div>
    ))}
  </div>
);
Enter fullscreen mode Exit fullscreen mode

Application component is wrapped with ConfigProvider component to set a custom theme.

const App: React.FC = () => (
  <ConfigProvider theme={customTheme}>
    <CssTokenBridge />
    <Test />
  </ConfigProvider>
);
Enter fullscreen mode Exit fullscreen mode

CssTokenBridge is a component for passing token values to CSS variables:

import { theme } from 'antd';
import { forEach, includes, isNumber, isString, kebabCase } from 'lodash';
import React from 'react';

function saveToken(value, tokenName) {
  const isPrivateField = tokenName.startsWith('_');
  if (isPrivateField) return;
  const variableName = `--antd-${kebabCase(tokenName)}`;
  if (isString(value)) document.documentElement.style.setProperty(variableName, value);
  if (isNumber(value)) {
    const propertyValue = isPureNumberProperty(tokenName) ? value : `${value}px`;
    document.documentElement.style.setProperty(variableName, propertyValue);
  }
}

const isPureNumberProperty = (tokenName) =>
  includes(tokenName, 'zIndex') ||
  includes(tokenName, 'Weight') ||
  includes(tokenName, 'motion') ||
  includes(tokenName, 'opacity') ||
  includes(tokenName, 'lineHeight');

export const CssTokenBridge = () => {
  const { token } = theme.useToken();
  React.useLayoutEffect(() => {
    forEach(token, saveToken);
  }, [ token ]);

  return null;
};
Enter fullscreen mode Exit fullscreen mode

I use kebab case names for CSS variable names and add an antd prefix. So, the colorPrimary token is saved to the β€” antd-color-primary CSS variable. There is a workaround for defining units of token value. Most of the numeric tokens use px units, but some of them should be just numbers (like zIndex, lineHeight). The isPureNumberProperty function should return true for such tokens.

Now, we can easily use Design System token values without hard-coded values in styles.

.app {
  display: flex;
  gap: var(--antd-padding-content-horizontal);

  .container {
    background-color: var(--antd-green-1);
    border-radius: var(--antd-border-radius);
    box-shadow: var(--antd-box-shadow);
    padding: var(--antd-padding);
  }
}
Enter fullscreen mode Exit fullscreen mode

Rendered layout

One of the advantages of this approach is that it’s easy to supervise design. Token name and its value is available in DevTools.

DevTools with CSS variables in styles

Hope the next versions of AntD will support css variables for dynamically changed custom themes out of the box.

Repository https://github.com/mvp-v/antd-css-vars

Top comments (0)