Radius overrides
Use the appearance corners setting to choose a radius preset for the whole
theme. For a smaller area, set data-radius on a wrapper. To change the radius
used by buttons within that area, override --nx-radius-base.
Button currently uses nx:rounded-base, which reads --nx-radius-base.
Input and SelectTrigger use nx:rounded-md, which reads --nx-radius-md.
The generic base name describes a token, not permanent ownership by Button:
any consumer of that token inside the scope receives the override.
Some components render Button with their own radius class, which replaces
rounded-base. These ignore the override:
- InputGroupButton at sizes
xs,icon-xs(rounded-sm) andsm(rounded-md). Sizeicon-smfollows the override. - Carousel previous and next buttons (
rounded-full). - DatePicker selected days:
rounded-mdat a range start and end,rounded-nonein the middle of a range, androunded-l-mdorrounded-r-mdon the outer side of any selected day at a week edge. A single selected day away from a week edge, unselected days and the month navigation buttons follow the override.
Rounded buttons, unchanged inputs
Under round, both base and medium radii start at 12px. This example changes
base to 9999px, leaving medium at 12px.
Use the component import paths from your installation. The local style type accepts this custom property without changing React's global types.
import type { CSSProperties } from 'react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Select, SelectTrigger, SelectValue } from '@/components/ui/select';
type RadiusStyle = CSSProperties & { '--nx-radius-base': string };
const pillButtons: RadiusStyle = { '--nx-radius-base': '9999px' };
export function RoundedActions() {
return (
<div data-radius="round" style={pillButtons}>
<Button>Save changes</Button>
<Input aria-label="Name" />
<Select>
<SelectTrigger aria-label="Category">
<SelectValue placeholder="Choose a category" />
</SelectTrigger>
</Select>
</div>
);
}The example demonstrates the closed Select trigger; add SelectContent and
SelectItem when providing choices. For one Button, put style={pillButtons}
on that Button instead. Existing className and style customization remains
available. Removing the override restores the inherited preset value.
Nested scopes and precedence
| Placement | Result |
|---|---|
| Override on a wrapper | Descendant consumers inherit it; siblings outside the wrapper do not. |
| Nested wrapper without a preset or override | Keeps inheriting the outer override. |
| Nested wrapper with its own override | Its descendants receive the nested value. |
Nested data-radius="smooth" | Declares fresh preset values, replacing an inherited override; Button returns to 8px. |
data-radius="round" and an inline base override on the same wrapper | The inline override wins over the preset's normal selector declaration. Medium remains 12px. |
These scopes follow the actual DOM ancestry. Content rendered into a portal outside the wrapper does not inherit the wrapper's variables.
ButtonGroup still removes the touching corners of adjacent children, in both
horizontal and vertical groups. In a group of only Buttons, the override rounds
the outside corners while the joining edges stay square. ButtonGroupText, Input
and SelectTrigger keep rounded-md, so a group mixing them with Buttons shows
different outside corners at each end. Button rendered with asChild passes
its styling to the child element as usual.
For the overall appearance model, see Appearance. The Tokens / Radius overrides / Scope And Precedence Storybook story checks the computed corners for these examples, including unchanged Input and SelectTrigger corners.