TLDR
- Legacy all-corners numeric classes (
d-bar6,d-bar8, etc.) are deprecated in favor of token-stop-indexed names (d-bar-350,d-bar-400, etc.). - Legacy physical side-pair classes (
d-btr*,d-bbr*,d-blr*,d-brr*) are deprecated in favor of logical side-pair classes (d-bbsr*,d-bber*,d-bisr*,d-bier*). - Pair keywords migrate too:
d-btr-pilltod-bbsr-pill,d-brr-circletod-bier-circle. - Run dialtone-migrate-border-radius for a radius-only batch migration, then use the ESLint rule to catch reintroductions in Vue templates.
- If you're already running
dialtone-migration-helper, itsutility-class-to-token-stopsconfig covers these rewrites.
Why Logical?
- RTL and internationalization. Logical names respect writing direction:
inline-startmeans the start edge regardless of locale. In other words,leftbecomesinline-startin LTR. - CSS alignment. The class names align with CSS logical properties such as
border-start-start-radiusandborder-end-end-radius. - Token consistency. Numeric suffixes now reference the
--dt-size-radius-{stop}token scale instead of legacy pixel suffixes.
What Changed
Border-radius utilities now use token stops and logical class roots. The generated CSS co-selects the legacy and new selectors, so both currently resolve to the same declaration, e.g...
.d-bbsr-350,
.d-btr6 {
border-start-start-radius: var(--dt-size-radius-350) !important;
border-start-end-radius: var(--dt-size-radius-350) !important;
}
Single-corner utilities (d-bssr-*, d-bser-*, d-besr-*, d-beer-*) are also available. They have no legacy physical equivalent.
Pair-Prefix Mapping
| Legacy physical prefix | New logical prefix | CSS properties | Visible side in LTR |
|---|---|---|---|
btr (top) | bbsr (block-start) | border-start-start-radius, border-start-end-radius | Top |
bbr (bottom) | bber (block-end) | border-end-start-radius, border-end-end-radius | Bottom |
blr (left) | bisr (inline-start) | border-start-start-radius, border-end-start-radius | Left |
brr (right) | bier (inline-end) | border-start-end-radius, border-end-end-radius | Right |
Numeric Stop Mapping
All-corners classes and side-pair classes use the same radius stop scale:
| Old suffix | New stop | Value |
|---|---|---|
0 | 0 | 0px |
1 | 100 | 1px |
2 | 200 | 2px |
4 | 300 | 4px |
6 | 350 | 6px |
8 | 400 | 8px |
12 | 450 | 12px |
16 | 500 | 16px |
24 | 550 | 24px |
32 | 600 | 32px |
Examples
All-Corners Numeric
Before
<div class="d-bar6">...</div>
<div class="d-bar8">...</div>
<div class="d-bar24">...</div>
After
<div class="d-bar-350">...</div>
<div class="d-bar-400">...</div>
<div class="d-bar-550">...</div>
Top Pair to Block-Start Pair
Before
<div class="d-btr6">...</div>
<div class="d-btr-pill">...</div>
<div class="d-btr-circle">...</div>
After
<div class="d-bbsr-350">...</div>
<div class="d-bbsr-pill">...</div>
<div class="d-bbsr-circle">...</div>
Bottom Pair to Block-End Pair
Before
<div class="d-bbr8">...</div>
<div class="d-bbr-pill">...</div>
<div class="d-bbr-circle">...</div>
After
<div class="d-bber-400">...</div>
<div class="d-bber-pill">...</div>
<div class="d-bber-circle">...</div>
Left Pair to Inline-Start Pair
Before
<div class="d-blr12">...</div>
<div class="d-blr-pill">...</div>
<div class="d-blr-circle">...</div>
After
<div class="d-bisr-450">...</div>
<div class="d-bisr-pill">...</div>
<div class="d-bisr-circle">...</div>
Right Pair to Inline-End Pair
Before
<div class="d-brr16">...</div>
<div class="d-brr-pill">...</div>
<div class="d-brr-circle">...</div>
After
<div class="d-bier-500">...</div>
<div class="d-bier-pill">...</div>
<div class="d-bier-circle">...</div>
Mixed Usage
Before
<div class="d-p-200 d-bgc-primary d-bar8 d-bs-sm">
<div class="d-btr6 d-bgc-moderate">Header</div>
<div class="d-bbr-pill">Footer</div>
</div>
After
<div class="d-p-200 d-bgc-primary d-bar-400 d-bs-sm">
<div class="d-bbsr-350 d-bgc-moderate">Header</div>
<div class="d-bber-pill">Footer</div>
</div>
What's Not Affected
- All-corners keyword classes (
d-bar-pill,d-bar-circle,d-bar-unset) keep their names. - Already-logical side-pair classes (
d-bbsr-*,d-bber-*,d-bisr-*,d-bier-*) are already canonical. - Single-corner logical classes (
d-bssr-*,d-bser-*,d-besr-*,d-beer-*) are canonical and have no old physical equivalent. - CSS custom properties are not renamed by this border-radius migration. This page covers utility classes.
Migration Script
For radius-only migrations:
npx dialtone-migrate-border-radius --dry-run --cwd ./src
Apply the changes after reviewing the file list:
npx dialtone-migrate-border-radius --cwd ./src
Skip the confirmation prompt:
npx dialtone-migrate-border-radius --yes --cwd ./src
The script scans .vue, .md, .html, .js, .ts, .jsx, and .tsx files and rewrites literal class names in static attributes, string literals, object/array class bindings, and simple template literals:
Before
<template>
<div class="d-bar6 d-btr8" />
<div :class="{ 'd-bbr-pill': rounded }" />
</template>
<script setup>
const headerClass = `d-btr6 ${extraClass}`;
</script>
After
<template>
<div class="d-bar-350 d-bbsr-400" />
<div :class="{ 'd-bber-pill': rounded }" />
</template>
<script setup>
const headerClass = `d-bbsr-350 ${extraClass}`;
</script>
Broader Utility-Class Migration
The dialtone-migration-helper utility-class-to-token-stops config also includes these border-radius rewrites. Use it if you're already migrating sizing, spacing, gap, and position classes in the same pass:
npx dialtone-migration-helper --cwd ./src
# Select "utility-class-to-token-stops"
Unlike the radius-only script, it also scans .mdx, .less, and .css and covers other utility families.
ESLint Rule
deprecated-radius-utility-classes flags deprecated radius classes in static Vue template class attributes and auto-fixes them to the canonical names.
Add it to your ESLint config:
// eslint.config.js (flat config)
import dialtone from '@dialpad/eslint-plugin-dialtone';
export default [
{
plugins: { dialtone },
rules: {
'dialtone/deprecated-radius-utility-classes': 'warn',
},
},
];
Then run:
npx eslint --fix "src/**/*.vue"
The rule handles static class attributes in Vue templates and preserves double quotes, single quotes, or unquoted attributes. It's a Vue-template guardrail, not a codemod replacement: it skips :class bindings, JS/TS strings, Markdown, and stylesheet files.
What Requires Manual Review
The tools are intentionally conservative. Search for the remaining patterns below after the automated pass.
| Pattern | Example | Why manual |
|---|---|---|
| Constructed class names | `d-btr${size}`, 'd-' + side + radius | No complete legacy class exists in source text. Update the source data or class-building logic. |
| Variant-prefixed utility classes | sm:d-bar6, md:d-btr8, h:d-brr-pill | The current radius codemod and ESLint rule match unprefixed utility classes only. |
| Custom wrappers around class names | const topRadius = 'btr6' | The tools only rewrite full Dialtone class names such as d-btr6. |
| Stylesheets with legacy class references | .card { @apply d-bar6; } | The radius-only script does not scan .css or .less. Use utility-class-to-token-stops or update manually. |
Final check:
rg -n "d-(bar(0|1|2|4|6|8|12|16|24|32)|(btr|bbr|blr|brr)(0|1|2|4|6|8|12|16|24|32)|(btr|bbr|blr|brr)-(pill|circle))" src
Migrate any matches to the canonical class.