Combining AntDesign and TailwindCSS

It has nothing to do with creating ant colonies

The Why?

I’m working on a project which I would like to ship as fast as possible, as I want to validate my idea with an MVP and some beta users. Therefore, I opted for a component/design library (for React). After evaluating a few, I found AntDesign to be the best fit for this project. But I wanted to keep the flexibility of TailwindCSS, as a component library might not provide everything I need out of the box and I might need some customizations.

There are two options, with current versions (Tailwind 3.3.3., AntDesign 5.7.0.) to have a consistently designed app:

  1. modify TailwindCSS default theme to match AntDesign or

  2. modify the AntDesign theme to match TailwindCSS

There is also a third option, which I find so wrong, that I won’t even list above: leave everything as is, and just work on your code, fixing styling issues on a case-by-case basis as you notice them. You can imagine what a mess this leaves after a while!

In my case I didn’t want to change anything, I wanted to use Ant Design as it is and make my TailwindCSS “respect” that, without losing the flexibility of utility classes TailwindCSS provides.

On a side note, if you are considering AntDesign, make sure you learn some Chinese, as the documentation is not completely translated into English!

The How?

First, you should go to https://ant.design/theme-editor. Here you can edit your AntDesign theme. I don’t want to make any adjustments, so I’m just looking for default values. Of course, if you would like to have a custom theme, now is the time to customize AntDesign. We will then transfer all those values into our tailwind.config.js configuration file.

In the AntDesign theme editor, they use camelCase, while the default in TailwindCSS is kebab-case. Since we are making changes to TailwindCSS we will respect the target styles, so that our class values look like those of TailwindCSS (bg-white, bg-color-primary-bg), while keeping the names to remind us of the respective AntDesign theme value. For example, color-primary-bg in TailwindCSS would be colorPrimaryBg in AntDesign. This way we won’t lose track of what is what, and if we decide to change those values later, we know where to look for them.

You can either extend TailwindCSS's color palette, or you can completely replace it with AntDesign colors. If you just want to add AntDesign colors, while preserving TailwindCSS's colors, make sure to add them under extend in tailwind.config.js instead of under colors, like this:

module.exports = {
  content: ['./src/**/*.{js,ts,jsx,tsx}'],
  darkMode: 'class',
  theme: {
    extend: {
      colors: {
        'color-primary-bg': '#e6f4ff',
        'color-primary-bg-hover': '#bae0ff',
        'color-primary-border': '#91caff',
        'color-primary-border-hover': '#69b1ff',
        'color-primary-hover': '#4096ff',
        'color-primary': '#1677ff',
        'color-primary-active': '#0958d9',
        'color-primary-text-hover': '#4096ff',
        'color-primary-text': '#1677ff',
        'color-primary-text-active': '#0958d9',
        'color-success-bg': '#f6ffed',
        'color-success-bg-hover': '#d9f7be',
        'color-success-border': '#b7eb8f',
        'color-success-border-hover': '#95de64',
        'color-success-hover': '#95de64',
        'color-success': '#52c41a',
        'color-success-active': '#389e0d',
        'color-success-text-hover': '#73d13d',
        'color-success-text': '#52c41a',
        'color-success-text-active': '#389e0d',
        'color-warning-bg': '#fffbe6',
        'color-warning-bg-hover': '#fff1b8',
        'color-warning-border': '#ffe58f',
        'color-warning-border-hover': '#ffd666',
        'color-warning-hover': '#ffd666',
        'color-warning': '#faad14',
        'color-warning-active': '#d48806',
        'color-warning-text-hover': '#ffc53d',
        'color-warning-text': '#faad14',
        'color-warning-text-active': '#d48806',
        'color-error-bg': '#fff2f0',
        'color-error-bg-hover': '#fff1f0',
        'color-error-border': '#ffccc7',
        'color-error-border-hover': '#ffa39e',
        'color-error-hover': '#ff7875',
        'color-error': '#ff4d4f',
        'color-error-active': '#d9363e',
        'color-error-text-hover': '#ff7875',
        'color-error-text': '#ff4d4f',
        'color-error-text-active': '#d9363e',
        'color-text': 'rgba(0, 0, 0, 0.88)',
        'color-text-secondary': 'rgba(0, 0, 0, 0.65)',
        'color-text-tertiary': 'rgba(0, 0, 0, 0.45)',
        'color-text-quaternary': 'rgba(0, 0, 0, 0.25)',
        'color-border': '#d9d9d9',
        'color-border-secondary': 'f0f0f0',
        'color-fill': 'rgba(0, 0, 0, 0.15)',
        'color-fill-secondary': 'rgba(0, 0, 0, 0.06)',
        'color-fill-tertiary': 'rgba(0, 0, 0, 0.04)',
        'color-fill-quaternary': 'rgba(0, 0, 0, 0.02)',
        'color-bg-container': '#ffffff',
        'color-bg-elevated': '#ffffff',
        'color-bg-layout': '#f5f5f5',
        'color-bg-spotlight': 'rgba(0, 0, 0, 0.85)',
        'color-bg-mask': 'rgba(0, 0, 0, 0.45)',
      },
      fontSize: {
        'font-size-sm': '12px',
        'font-size-lg': '16px',
        'font-size-xl': '20px',
        'font-size-heading1': '38px',
        'font-size-heading2': '30px',
        'font-size-heading3': '24px',
        'font-size-heading4': '20px',
        'font-size-heading5': '16px',
      },
      lineHeight: {
        'line-height': '1.5714285714285714',
        'line-height-sm': '1.6666666666666667',
        'line-height-lg': '1.5',
        'line-height-heading1': '1.2105263157894737',
        'line-height-heading2': '1.2666666666666666',
        'line-height-heading3': '1.3333333333333333',
        'line-height-heading4': '1.4',
        'line-height-heading5': '1.5',
      },
      margin: {
        'margin-xxs': '4px',
        'margin-xs': '8px',
        'margin-sm': '12px',
        margin: '16px',
        'margin-md': '20px',
        'margin-lg': '24px',
        'margin-xl': '32px',
        'margin-xxl': '48px',
      },
      padding: {
        'padding-xxs': '4px',
        'padding-xs': '8px',
        'padding-sm': '12px',
        padding: '16px',
        'padding-md': '20px',
        'padding-lg': '24px',
        'padding-xl': '32px',
      },
      borderRadius: {
        'border-radius': '6px',
        'border-radius-sm': '4px',
        'border-radius-lg': '8px',
        'border-radius-xs': '2px',
      },
      boxShadow: {
        'box-shadow':
          '0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 9px 28px 8px rgba(0, 0, 0, 0.05)',
        'box-shadow-secondary':
          '0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 9px 28px 8px rgba(0, 0, 0, 0.05)',
      },
    },
  },
  plugins: [],
};

This way I can now use those AntDesign styles in my code like this:

<Input
    className="rounded-border-radius w-full"
    size="large"
    placeholder="Enter link here"
    value={link}
    onChange={handleLinkChange}
    onKeyDown={handleKeyDown}
/>

If you’ve used TailwindCSS, you know that we set border-radius with a rounded utility class. Only now we can provide our AntDesign variable as a suffix, like this rounded-border-radius and keep using other utility classes, like w-full as we normally would. Beautiful!

Thanks for reading. If you found this helpful, please give a ❤️.

Did you find this article valuable?

Support Samir Alibabic by becoming a sponsor. Any amount is appreciated!