| type | reference | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| category | reference | ||||||||||||
| keywords |
|
||||||||||||
| ai_summary | Cross-component API contract for Dialtone Vue components — standard props, events, slots, and patterns shared by all components. | ||||||||||||
| last_updated | 2026-03-09 | ||||||||||||
| related_packages |
|
Every Vue component in packages/dialtone-vue/components/ follows shared conventions. This document describes the implicit contract so you know what to expect from any component without reading its source.
Every component has a {component_name}_constants.js file that exports modifier maps. These map prop values to CSS class names:
// button_constants.js
export const BUTTON_SIZE_MODIFIERS = {
xs: 'd-btn--xs',
sm: 'd-btn--sm',
md: '', // default size — no modifier class needed
lg: 'd-btn--lg',
xl: 'd-btn--xl',
};The Vue component validates props against these maps and applies the corresponding class. The empty string '' convention means "default, no extra class."
Constants are also re-exported from each component's index.js so consumers can import them.
Most sizable components accept a size prop with values: xs, sm, md, lg, xl. Default is usually md.
Exceptions exist — DtModal uses default and full instead.
Color or semantic variant. Values vary per component:
- DtButton:
default,muted,danger,positive,inverted,unstyled - DtModal:
default,danger - DtNotice:
base,error,info,success,warning - DtBadge: uses
typeinstead (default,info,success,warning,critical,bulletin,ai)
Visual weight. Currently specific to DtButton: clear, outlined, primary. Other components do not use this prop.
All components accept class override props typed as [String, Array, Object]:
- DtButton →
labelClass - DtInput →
inputClass - DtAvatar →
avatarClass - DtModal →
modalClass - DtToggle →
labelClass
These are bound with Vue's :class binding on the inner element, separate from the root element's class prop.
All form components implement Vue 3 v-model via modelValue prop + update:modelValue emit:
| Component | modelValue type | Notes |
|---|---|---|
| DtInput | String | Number |
Also emits update:length, update:invalid |
| DtCheckbox | Boolean |
Via CheckableMixin |
| DtRadio | String | Number |
Via CheckableMixin |
| DtSelectMenu | String | Number |
|
| DtToggle | Boolean | String |
Supports 'mixed' for indeterminate state |
Visibility-toggle components use update:open:
| Component | Emit |
|---|---|
| DtModal | update:open |
| DtTooltip | update:open |
| DtToast | update:open |
| DtPopover | update:open |
| DtDropdown | update:open |
Native DOM events are forwarded as-is: focus, blur, focusin, focusout, input, click, keydown.
Custom events use the update:{prop} convention to stay compatible with v-model:
update:modelValue — value changed
update:open — visibility changed
update:length — input length changed (DtInput)
update:invalid — validation state changed (DtInput)
| Slot name | Used by | Purpose |
|---|---|---|
default |
All components | Primary content |
icon |
Button, Badge, Avatar | Single icon placement |
leftIcon / rightIcon |
Input | Directional icon slots |
header / footer |
Modal | Section slots |
banner |
Modal | Top banner area |
anchor |
Tooltip, Popover | Trigger element |
description |
Input, Checkbox | Helper/description text |
Icon slots pass sizing data via slot props:
<slot name="icon" :icon-size="iconSize" />Each component with icons maps its size prop to an icon scale via a *_ICON_SIZES constant. The mapping is component-specific, not global:
| Component size | Button icon | Input icon | Avatar icon |
|---|---|---|---|
| xs | 200 | 100 | 100 |
| sm | 200 | 200 | 200 |
| md | 300 | 200 | 300 |
| lg | 400 | 400 | 500 |
| xl | 500 | 500 | 600 |
Icon scale values correspond to pixel sizes defined in packages/dialtone-icons/src/constants.js:
| Scale | Pixels |
|---|---|
| 100 | 12px |
| 200 | 14px |
| 300 | 18px |
| 400 | 20px |
| 500 | 24px |
| 600 | 32px |
| 700 | 38px |
| 800 | 48px |
Group-child relationships use Vue's provide/inject. The parent provides a reactive context object plus action methods:
Tab group (tab_group.vue):
provides: { groupContext: { selected, disabled }, setFocus }
Input groups (CheckboxGroup, RadioGroup via input_group.js mixin):
provides: { groupContext: { name, disabled, validationState, value, selectedValues }, setGroupValue }
Child components inject with defaults so they also work standalone:
inject: {
groupContext: { default: {} },
setGroupValue: { default: () => () => {} },
}DtModal uses Vue's native <teleport> with an appendTo prop (CSS selector string). When appendTo is undefined, the modal renders in-place.
DtTooltip, DtPopover, and DtHovercard use Tippy.js with a similar appendTo prop that defaults to 'body'.
All components use data-qa attributes for test selectors. Pattern: dt-{component} for the root, dt-{component}-{element} for children:
data-qa="dt-button"
data-qa="dt-button-icon"
data-qa="dt-button-label"
data-qa="dt-modal-title"
data-qa="dt-input-label"
Tests query these with wrapper.find('[data-qa="dt-button"]').
Some components validate prop combinations at runtime and log warnings. There is no shared validation framework — each component implements its own checks in watch or mounted():
- DtButton: warns on
circle + linkconflict, invalidkind + importancecombinations - DtBadge: errors on
type: 'ai'withkind: 'count', decoration with non-default type/kind - DtAvatar: errors when
imageSrcis provided withoutimageAlt - DtTooltip: warns when both
enabledandshowprops are set
Check each component's source or _constants.js for the full list of invalid combinations.