TLDR
- Slots, props, prop values, and events now use logical direction names:
start,end,blockStart,blockEnd. - Physical names (
left,right,top,bottom,alpha,omega) still work. This is not a breaking change. - Use the ESLint rule or migration script to update your code.
- Manual migration required: The
#iconslot ondt-button. See below.
Why Logical?
- RTL and internationalization. Logical names respect writing direction:
startmeans the inline-start edge regardless of locale. - CSS alignment. Matches CSS logical properties (
margin-inline-start,padding-block-end) that Dialtone already uses internally. - Consistency. One naming convention across tokens, CSS utilities, and Vue components.
Examples
Slots
Before
<dt-badge>
<template #leftIcon>...</template>
</dt-badge>
<dt-item-layout>
<template #left>...</template>
<template #right>...</template>
<template #bottom>...</template>
</dt-item-layout>
<dt-split-button>
<template #alphaIcon>...</template>
<template #omegaIcon>...</template>
</dt-split-button>
After
<dt-badge>
<template #startIcon>...</template>
</dt-badge>
<dt-item-layout>
<template #start>...</template>
<template #end>...</template>
<template #blockEnd>...</template>
</dt-item-layout>
<dt-split-button>
<template #startIcon>...</template>
<template #endIcon>...</template>
</dt-split-button>
Props
Before
<dt-item-layout
left-class="d-bgc-critical"
right-class="d-bgc-warning"
bottom-class="d-bgc-info"
/>
<dt-split-button
alpha-active
alpha-aria-label="Call"
omega-disabled
/>
After
<dt-item-layout
start-class="d-bgc-critical"
end-class="d-bgc-warning"
block-end-class="d-bgc-info"
/>
<dt-split-button
start-active
start-aria-label="Call"
end-disabled
/>
Prop Values
Before
<dt-button icon-position="left">
...
</dt-button>
<dt-root-layout sidebar-position="right" />
After
<dt-button icon-position="start">
...
</dt-button>
<dt-root-layout sidebar-position="end" />
Events
Before
<dt-split-button
@alpha-clicked="onPrimary"
@omega-clicked="onSecondary"
/>
After
<dt-split-button
@start-clicked="onPrimary"
@end-clicked="onSecondary"
/>
Manual Migration: dt-button #icon Slot
The #icon slot on dt-button is ambiguous: its position depends on the iconPosition prop. The migration tools skip this case. Replace #icon with the slot matching your intended position:
| iconPosition value | Replacement slot |
|---|---|
start (default) | #startIcon |
end | #endIcon |
blockStart | #blockStartIcon |
blockEnd | #blockEndIcon |
Before
<dt-button icon-position="start">
<template #icon>
<dt-icon name="phone" />
</template>
Call
</dt-button>
After
<dt-button icon-position="start">
<template #startIcon>
<dt-icon name="phone" />
</template>
Call
</dt-button>
What's Affected
Components: DtBadge, DtButton, DtInput, DtTab, DtSplitButton, DtItemLayout, DtRootLayout
Recipes: Callbox, Contact Centers Row, General Row, Top Banner Info, Grouped Chip
ESLint Rule
deprecated-physical-naming flags all deprecated physical slot, prop, prop value, and event usage on Dialtone components.
Add to your ESLint config:
// eslint.config.js (flat config)
import dialtone from '@dialpad/eslint-plugin-dialtone';
export default [
{
plugins: { dialtone },
rules: {
'dialtone/deprecated-physical-naming': 'warn',
},
},
];
Migration Script
Run the migration helper from your project root:
npx dialtone-migration-helper --cwd ./src
Select "physical-to-logical" from the config list. This renames all unambiguous physical names to their logical equivalents across .vue, .md, .html, .js, .ts, .jsx, and .tsx files.
To apply changes without interactive confirmation:
npx dialtone-migration-helper --cwd ./src --force
The script handles: slot directives, prop names, prop values, and event listeners for all affected components.
Skipped: The #icon slot on dt-button (ambiguous), dynamic bindings, and script-block references.