NuvoUI vs Ant Design
Ant Design (antd) is a React component library. NuvoUI core is a CSS foundation layer with no components. They are not substitutes, so this page compares what they share: design tokens, theming and direction support.
Different categories
antd gives a React application finished, interactive components. NuvoUI core gives any project the layer below components: tokens, themes, layout and utilities. Choosing antd means choosing React and the Ant Design specification. Choosing NuvoUI core means building the components yourself.
Who should pick which
Pick Ant Design if
- You build a React application (React 18 or later [3]) and need finished components now: antd provides a set of React components out of the box, written in TypeScript [2].
- You want theme changes at runtime from JavaScript: the
themeprop ofConfigProvidertakes tokens and algorithms, and supports switching at runtime [4]. - You want derived tokens: antd derives Map tokens from Seed tokens and Alias tokens from Map tokens, so one seed such as
colorPrimarychanges many components [4]. - You need built-in internationalisation for dozens of languages [2].
- You want a mature component library with a long release history [9].
Pick NuvoUI if
- You are not on React, or you want styling that works with any framework or none: NuvoUI compiles to plain CSS.
- You are building your own components or design system and want a foundation layer: utilities,
apply()mixins and tokens. - You want no styling code at runtime: NuvoUI is SCSS only, compiled by Dart Sass, with no JavaScript.
- You want utility classes for layout and spacing in your own markup, including logical RTL utilities.
Side by side
| Topic | Ant Design | NuvoUI |
|---|---|---|
| Category | "An enterprise-class UI design language and React UI library" [1]: a set of React components out of the box [2]. | A CSS foundation layer in SCSS: utilities, mixins and design tokens. It has no components; plain HTML buttons and form fields get base styles. |
| Philosophy | Components implement the Ant Design specification; you compose React components and configure them with props [2]. | You write the markup and style it with human-readable utilities, or build component classes with apply(). |
| Syntax | JSX with props: <Button type="primary">, <Card title="..." extra={...}> [5]. Since 5.21, Button also takes variant and color [6]. | Classes on your own elements (flex col gap-3 p-6 bg-surface, p-8@lg), or mixins in SCSS (apply(p(6), shadow(md) hover)). |
| Customisation | ConfigProvider theme prop: global tokens under token (for example colorPrimary), component tokens under components [4][7]. | Sass configuration in the first @use ... with (...): $brand, scale maps, theme override maps and feature flags, validated at compile time. |
| Theming and dark mode | Algorithms: theme.darkAlgorithm and theme.compactAlgorithm, which can be combined [4]. | data-theme="light", "dark" or "inverse" on any element, with an operating system fallback; pure CSS. A [data-contrast="high"] hook applies override maps; both maps are empty by default. No compact mode. |
| RTL | <ConfigProvider direction="rtl"> sets the layout direction of the components [7]. | Logical utilities and mixins (ms, me, ps, pe, start-*, end-*, border-s, text-start) that follow the dir attribute, alongside physical ones. |
| Design tokens | Three layers: Seed, Map and Alias tokens, plus component tokens. Read them with the useToken hook in React or getDesignToken outside it [4]. | --nu-* CSS custom properties: surfaces, text, borders, focus, brand and status roles, palette and scales. Each role and hue gets an OKLCH scale from 50 to 950, and themes point roles at different stops. |
| Build requirements | React 18 or later [3]. Theme customisation is built on CSS-in-JS [1]; server rendering extracts styles with @ant-design/cssinjs or generates a static file with @ant-design/static-style-extract [8]. | Dart Sass 1.79 or later (below 2.0). No JavaScript, no runtime and no PostCSS plugin. |
| Bundle approach | Styles are part of the components and themed through CSS-in-JS [1]. v6 uses CSS variables by default and supports modern browsers only; IE is not supported [3]. | With $generate-utility-classes: true every configured class is emitted (about 1 MB minified, 93 KB gzipped with the defaults), so purge unused classes or switch feature flags off. Mixin-only use emits what you write plus about 43 KB of base CSS per compiled entry. |
| JS components | The core of the product: React components with TypeScript types [2]. | None. Core is a foundation layer with no component library; it includes CSS-only tooltips. |
| Ecosystem | Design resources and development tools, and internationalisation for dozens of languages [2]. The introduction invites the community to implement the design system in other frameworks; antd itself is React only [2]. | Small: the core package and its documentation. No plugin ecosystem. |
| Licence | MIT [10]. | MIT. |
The same component in both
A card with a title, text and a primary action, plus a theme with a custom brand colour and dark mode. In antd the card and button are components and the theme is a React prop. In NuvoUI the markup is yours, the classes read theme tokens and the theme is Sass configuration plus a data-theme attribute.
import { Button, Card } from 'antd';
<Card title="Card title" extra={<a href="#">More</a>} style={{ width: 300 }}>
<p>Some quick example text.</p>
<Button type="primary">Go somewhere</Button>
</Card><section data-theme="dark">
<div class="flex col gap-3 p-6 bg-surface border rounded-lg">
<h3 class="text-lg font-semibold">Card title</h3>
<p class="text-muted">Some quick example text.</p>
<button type="button" class="self-start bg-brand text-on-brand">Go somewhere</button>
</div>
</section>import { ConfigProvider, theme } from 'antd';
<ConfigProvider
theme={{
token: { colorPrimary: '#1677ff' },
algorithm: theme.darkAlgorithm,
}}
>
<App />
</ConfigProvider>@use "@nuvoui/core" as * with (
$brand: #1677ff,
$light-theme: ("brand": brand 600),
$dark-theme: ("bg-base": #141414)
);
.note {
padding-inline: token(space-4);
color: token(text-muted);
}Moving from Ant Design
- Map antd theme tokens to Sass configuration:
colorPrimarycorresponds to$brand, and per-theme values go in$light-themeand$dark-theme. See Configuration and Theming. - Replace
theme.darkAlgorithmwithdata-theme="dark"on the root or on a section. See Theming. - Replace
direction="rtl"withdir="rtl"on the document, and use logical utilities in your markup. See Spacing. - Components have to be built: write them with
apply()or utility classes. See apply() and the A to Z reference. - Read token names and default values in Tokens.
Sources
Every statement about Ant Design on this page comes from its official documentation or repository. Statements about NuvoUI come from the core source, its changelog and the core documentation.
- [1] Ant Design repository READMEhttps://github.com/ant-design/ant-design
- [2] Ant Design: Introductionhttps://ant.design/docs/react/introduce
- [3] Ant Design: Migrate to v6https://ant.design/docs/react/migration-v6
- [4] Ant Design: Customize themehttps://ant.design/docs/react/customize-theme
- [5] Ant Design: Cardhttps://ant.design/components/card
- [6] Ant Design: Buttonhttps://ant.design/components/button
- [7] Ant Design: ConfigProviderhttps://ant.design/components/config-provider
- [8] Ant Design: Server-side renderinghttps://ant.design/docs/react/server-side-rendering
- [9] Ant Design releaseshttps://github.com/ant-design/ant-design/releases
- [10] Ant Design licencehttps://github.com/ant-design/ant-design/blob/master/LICENSE