nxds with Ant Design
Add nxds components to an Ant Design app, and keep antd for everything else. These steps use a Next.js App Router app on antd 6.
What nxds adds for you
nxds gives an antd app parts it doesn't have, themed from one appearance object. Introduction covers the theme engine, the copy-and-own source and the agent support.
| You need | nxds part |
|---|---|
| A command palette | CommandDialog |
| A collapsible app sidebar | Sidebar and SidebarProvider |
| A filter bar | FilterBuilder |
| A right-click menu or menu bar | ContextMenu and Menubar |
| A bottom sheet | Drawer |
| A select with several values | MultiSelect |
| Large radio or checkbox choices | ChoiceCard, ChoiceRow |
| A chart | ChartContainer |
| A chat thread | Message and Bubble |
Add your first nxds component
Set up nxds, then add a component:
init adds the provider and the theme script to app/layout.tsx, and creates
app/nxds.css. antd/dist/reset.css sets box-sizing. If your app imports
it, delete the Preflight lines in app/nxds.css, as
Add nxds to an existing app
explains. If your app has no reset, keep Preflight.
antd's component styles target only its own .ant- classes, so they need no
cascade layer. antd/dist/reset.css does style bare elements, such as
p { margin-bottom }. Load it into a layer below the nxds utilities:
Render the nxds button on an existing screen, beside antd's:
antd's popups sit at z-index 1000 to 1070. Raise the nxds layers above them, so an nxds popup opens over an antd modal:
Inside an nxds dialog, render antd popups in place with
getPopupContainer={(trigger) => trigger.parentElement ?? document.body}.
Share light and dark mode
nxds owns the mode. antd has no color mode of its own: it picks colors from
the algorithm you pass to ConfigProvider. Pick the algorithm from the nxds
mode:
antd renders its styles in React, so it can't read the nxds head script. Read the mode from a cookie in the root layout instead, so the server renders the right algorithm on the first request:
The provider writes the cookie each time the mode changes. Load the theme from a cookie explains the setup. Reading cookies renders every route on each request.
The server can't see the operating system's mode. When mode is 'system'
and the system is dark, antd paints light for a moment, then turns dark after
hydration. Set mode to 'light' or 'dark' to avoid it.
Switch the mode through nxds:
Match your theme
Keep the values both systems read in one file:
| antd token | Appearance field | How to match |
|---|---|---|
colorPrimary | brandColor | Pass it as is. nxds builds the hover and pressed shades |
colorBgBase, colorTextBase | surfaceTone | antd's grays are pure, so neutral matches |
borderRadius | corners | 0 is square, 2 to 4 is subtle, 6 to 8 is smooth, 10 to 12 is round, 16 is extra-round. antd's default is 6 |
compactAlgorithm, controlHeight, sizeStep | density | compactAlgorithm matches compact. Compare others in the Playground |
boxShadow | elevation | Compare in the Playground. flat turns shadows off |
lineWidth | stroke | 1 is normal, 2 is strong |
fontFamily | prefs.uiFont | Pass the same font stack |
fontSize | prefs.uiFontSize | Both default to 14 |
darkAlgorithm | mode | nxds owns it, as Share light and dark mode shows |
Where nxds fits
antd components take data props, such as items, options and columns.
nxds components take children: one part per item. nxds handlers take the value
itself: onValueChange(value), onCheckedChange(checked),
onOpenChange(open).
| Ant Design | nxds | What changes |
|---|---|---|
Button | Button | type primary, default, dashed, text, link → variant default, outline, dashed, ghost, link |
Button danger | Button variant="destructive" | |
Button with only an icon | Button size="icon" | Give it an aria-label |
Space.Compact with buttons | ButtonGroup | |
Form.Item | Field, FieldLabel, FieldDescription, FieldError | label, extra and help become parts. validateStatus="error" → data-invalid |
Input | Input in a Field | |
Input with prefix, suffix or addonBefore | InputGroup, InputGroupAddon, InputGroupInput | |
Input.TextArea | Textarea | |
Input.OTP | InputOTP, InputOTPGroup, InputOTPSlot | |
Checkbox | Checkbox with a FieldLabel | onChange(event) → onCheckedChange(checked) |
Checkbox.Group | Several Checkbox parts in a FieldGroup | |
Radio.Group, Radio | RadioGroup, RadioGroupItem | onChange(event) → onValueChange(value) |
Radio.Button, Segmented | ToggleGroup type="single" | onChange → onValueChange |
Switch | Switch | onChange(checked) → onCheckedChange(checked) |
Select | Select, SelectTrigger, SelectValue, SelectContent, SelectItem | options → SelectItem children. onChange → onValueChange(value) |
Select mode="multiple" | MultiSelect | onChange(values) → onValuesChange(values) |
AutoComplete, Select showSearch | Combobox | Compose a ComboboxTrigger, ComboboxInput and ComboboxItem list |
Slider | Slider | value is an array, with two values for range. onChange → onValueChange |
DatePicker | DatePicker in a Popover | Takes React Day Picker props: mode, selected, onSelect |
Calendar | DatePicker | |
Modal | Dialog, DialogContent, DialogHeader, DialogTitle, DialogBody, DialogFooter | onCancel → onOpenChange(open). footer → DialogFooter |
Modal.confirm, Popconfirm | AlertDialog | |
Drawer | Sheet, SheetContent | placement → side. onClose → onOpenChange(open) |
Dropdown | DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem | menu={{ items }} → DropdownMenuItem children |
Menu mode="inline" | SidebarMenu, SidebarMenuItem, SidebarMenuButton | |
Menu mode="horizontal" | NavigationMenu | |
Popover | Popover, PopoverTrigger, PopoverContent | content → PopoverContent children |
Tooltip | Tooltip, TooltipTrigger, TooltipContent | title → TooltipContent children |
message, notification | Toaster, toast() | message.success('Saved') → toast.success('Saved') |
Alert | Alert, AlertTitle, AlertDescription | type error, warning, info, success → variant destructive, warning, information, success |
Collapse | Accordion, AccordionItem, AccordionTrigger, AccordionContent | items → AccordionItem children. accordion → type="single" |
Tabs | Tabs, TabsList, TabsTrigger, TabsContent | items → children. onChange → onValueChange |
Breadcrumb | Breadcrumb, BreadcrumbList, BreadcrumbItem, BreadcrumbLink | items → BreadcrumbItem children |
Pagination | Pagination, PaginationContent, PaginationLink | |
Card | Card, CardHeader, CardTitle, CardAction, CardContent, CardFooter | title → CardTitle, extra → CardAction, actions → CardFooter |
Avatar, Avatar.Group | Avatar, AvatarImage, AvatarFallback, AvatarGroup | |
Tag | Badge | color → variant |
Tag closable | FilterChip | |
Divider | Separator | |
Progress | Progress | Line progress only |
Spin, Skeleton | Spinner, Skeleton | |
Table | Table, TableHeader, TableBody, TableRow, TableHead, TableCell | Render columns and dataSource as rows yourself |
Table rowSelection | TableSelectionHead, TableSelectionCell | |
Descriptions | DescriptionList, DescriptionListItem, DescriptionListTerm, DescriptionListDescription | |
Empty, Result | EmptyState | |
List | ItemGroup, Item, ItemTitle, ItemDescription | |
Carousel | Carousel, CarouselContent, CarouselItem | |
Splitter | ResizablePanelGroup, ResizablePanel, ResizableHandle | |
Layout.Sider | Sidebar | |
Flex, Space, Row, Col, Layout | nx: flex and grid classes | At the default density, gap small, middle, large → nx:gap-2, nx:gap-4, nx:gap-6 |
Typography.Title, Typography.Text | nx:typography-* classes | Such as nx:typography-heading-large and nx:typography-body-default |
Grid.useBreakpoint | Show and Hide | <Hide below="md"> hides content below the md breakpoint |
Swap a component (optional)
Swap a component when you touch the screen anyway. This form field moves from antd to nxds:
antd's Form validates the fields inside each Form.Item. Move a whole form
at once, or validate the nxds fields with your own form library. See
Forms.
To check the nx: classes in the files you move over, add the
nxds lint rules.
What stays on Ant Design
nxds has no part for these. Keep them on antd:
StepsRateTreeandTreeSelectCascaderTransferUploadTimePickerInputNumberandMentionsColorPickerTimelineTourStatistic,QRCode,ImageandWatermarkFloatButtonBadge, the count on an iconProgress type="circle"Tablewith sorting, filters or virtual scroll