Directive for scoping light, dark, or inverted color mode.
Use the v-dt-mode directive to control the color mode of a region, component, or element. It creates a scoped region with the specified mode. Descendant elements retain their original styling but are rendered with the specified mode.
<dt-text v-dt-mode:dark tone="positive"> Dark content </dt-text> <dt-text v-dt-mode:light tone="positive"> Light content </dt-text> <dt-text v-dt-mode:invert tone="positive"> Inverted — opposite of parent or root </dt-text>
This effectively removes the need for inverted props or variants on elements or components.
For example, instead of using inverted on a DtButton, use v-dt-mode:invert
<dt-button>Button</dt-button> <dt-button v-dt-mode:invert>Button</dt-button>
Bind a reactive variable as the directive arg to switch modes at runtime.
<dt-text v-dt-mode:{mode} align="center" tone="positive"> ... mode </dt-text>
Pass a boolean value to conditionally apply or remove the directive. When false, mode attributes are removed entirely.
<dt-button v-dt-mode:invert="isInverted">Button</dt-button>
[data-dt-mode="light"] and [data-dt-mode="dark"] attribute selectors[data-dt-mode][data-dt-contrast="high"]<html> element and kept in sync via MutationObserver<html> element the same way — data-dt-material propagates onto the island/directive element so --dt-color-black-* re-binds correctly inside inverted regionsinvert mode, the directive reads the nearest ancestor's data-dt-mode, computes the opposite, and reacts when it changesdata-dt-brand (theme) and data-dt-material cannot be overridden on mode islands — brand and material are root-level by design (material is paired to brand for visual coherence; see brand-locked materials)The default mode — inverts relative to the nearest parent mode boundary or the root. When no arg is provided, v-dt-mode defaults to invert.
<section v-dt-mode class="d-p-200 d-bar-400"> <dt-text as="p" tone="positive">Inverted mode (opposite of parent)</dt-text> </section>
Explicitly set to light mode regardless of parent or root mode.
<section v-dt-mode:light class="d-p-200 d-bar-400"> <dt-text as="p" tone="positive">Always light mode</dt-text> </section>
Explicitly set to dark mode regardless of parent or root mode.
<section v-dt-mode:dark class="d-p-200 d-bar-400"> <dt-text as="p" tone="positive">Always dark mode</dt-text> </section>
Mode boundaries can be nested. Each v-dt-mode:invert reads the nearest parent boundary and flips. In this example the first level is explicitly set to light mode, the second level inverts against that, and the third level inverts again.
<dt-stack gap="200" v-dt-mode:light class="d-p-200 d-bar-400 d-bgc-secondary d-ba"> <dt-text as="p" tone="positive" text-box-trim="both">Explicit Light</dt-text> <dt-stack v-dt-mode gap="200" class="d-p-200 d-bar-400 d-bgc-secondary"> <dt-text as="p" tone="positive" text-box-trim="both">Inverted (Dark)</dt-text> <dt-stack v-dt-mode gap="200" class="d-p-200 d-bar-300 d-bgc-secondary"> <dt-text as="p" tone="positive" text-box-trim="both">Inverted again (Light)</dt-text> </dt-stack> </dt-stack> </dt-stack>
The background surface of a Mode Island defaults to the root surface color. To override, use a CSS Utility class.
<dt-mode-island class="d-p-200 d-bar-400 d-w100p d-bgc-transparent"> <dt-stack gap="200"> <dt-text as="p" kind="code" :size="100" tone="tertiary">Transparent background, inverted mode island</dt-text> <div> <dt-button>Button</dt-button> </div> </dt-stack> </dt-mode-island> <dt-mode-island class="d-p-200 d-bar-400 d-w100p"> <dt-stack gap="200"> <dt-text as="p" kind="code" :size="100" tone="tertiary">Default background, inverted mode island</dt-text> <div> <dt-button>Button</dt-button> </div> </dt-stack> </dt-mode-island> <dt-mode-island mode="dark" class="d-p-200 d-bar-400 d-w100p d-bgc-critical"> <dt-stack gap="200"> <dt-text as="p" kind="code" :size="100" tone="tertiary">critical background, dark mode island</dt-text> <div> <dt-button>Button</dt-button> </div> </dt-stack> </dt-mode-island> <dt-mode-island mode="light" class="d-p-200 d-bar-400 d-w100p d-bgc-critical"> <dt-stack gap="200"> <dt-text as="p" kind="code" :size="100" tone="tertiary">critical background, light mode island</dt-text> <div> <dt-button>Button</dt-button> </div> </dt-stack> </dt-mode-island>
A real-world pattern: the callbar container already exists as a semantic element. The directive applies mode theming directly — no wrapper needed.
<dt-stack v-dt-mode class="d-ba d-bc-subtle d-bgc-secondary d-p-75 d-py-50 d-bar-450 d-bs-md d-w100p" direction="row" gap="400"> <dt-stack gap="100" direction="row"> <dt-avatar full-name="TA" seed="ted-anderson" :size="400" /> <dt-stack gap="25"> <dt-text kind="label" :size="300" density="200">Ted Anderson</dt-text> <dt-stack direction="row" gap="50" align="baseline"> <dt-text kind="body" :size="100" tone="tertiary" wrap="nowrap" numeric>(913) 555-6745</dt-text> <dt-text kind="body" :size="100" tone="muted">•</dt-text> <dt-text kind="body" :size="100" tone="tertiary" numeric>21:18</dt-text> </dt-stack> </dt-stack> </dt-stack> <dt-stack class="d-fl1" direction="row" gap="25" justify="center"> <dt-button class="d-px-100 d-w-100" :size="100" kind="critical"> <template #blockStartIcon> <dt-icon name="mic" size="300" /> </template> Unmute </dt-button> <dt-button class="d-px-100 d-w-100" :size="100" kind="muted" importance="clear"> <template #blockStartIcon> <dt-icon name="record-filled" size="300" /> </template> Record </dt-button> <dt-button class="d-px-100 d-w-100" :size="100" kind="muted" importance="clear"> <template #blockStartIcon> <dt-icon name="keypad" size="300" /> </template> Keypad </dt-button> <dt-button class="d-px-100 d-w-100" :size="100" kind="muted" importance="clear"> <template #blockStartIcon> <dt-icon name="user-plus" size="300" /> </template> Add </dt-button> <dt-button class="d-px-100 d-w-100" :size="100" kind="muted" importance="clear"> <template #blockStartIcon> <dt-icon name="more-horizontal" size="300" /> </template> More </dt-button> </dt-stack> <dt-stack> <dt-button class="d-p-150" circle :size="400" kind="critical"> <template #startIcon> <dt-icon name="phone-hang-up" size="500" /> </template> </dt-button> </dt-stack> </dt-stack> <dt-text as="p" kind="label" :size="200" tone="muted" class="d-mbs-100">* Not real, still just an example</dt-text>
Popovers, Dropdowns, Modals, and Hovercards render their content outside the normal DOM tree, so v-dt-mode on the component itself won't reach the positioned element. These components provide a contentMode prop that applies the mode directly to the positioned content.
<!-- Hovercard --> <dt-hovercard placement="top-start" content-mode="invert"> <template #anchor> <dt-button :size="200" kind="muted" importance="outlined">Default</dt-button> </template> <template #content> <ExampleProfileCard /> </template> </dt-hovercard> <!-- Popover --> <dt-popover content-mode="invert" placement="top-start" dialogClass="d-w-350"> <template #anchor> <dt-button :size="200" kind="muted" importance="outlined"> Inverted </dt-button> </template> <template #content="{ close }"> <dt-text as="p">This Popover content is in the <dt-text strength="strong">inverted</dt-text> mode.</dt-text> </template> </dt-popover> <!-- Dropdown --> <dt-dropdown content-mode="invert" navigation-type="arrow-keys" placement="bottom-start"> <template #anchor="{ attrs }"> <dt-button v-bind="attrs" :size="200" kind="muted" importance="outlined"> Inverted <template #endIcon="{ iconSize }"> <dt-icon name="chevron-down" :size="iconSize" /> </template> </dt-button> </template> <template #list="{ close }"> <dt-list-item v-for="item in items" :key="item.id" role="menuitem" :navigation-type="arrow - keys" @click="close" > {{ item.name }} </dt-list-item> </template> </dt-dropdown>
The <dt-mode-island> component is the underlying abstraction that the directive builds on. The key rendered difference is that it creates a wrapper element, while the directive attaches to mode to the existing element.
<dt-mode-island as="section"> Rendered as a section element inverted </dt-mode-island> <dt-mode-island> Inverted (default) </dt-mode-island> <dt-mode-island mode="light"> Light </dt-mode-island> <dt-mode-island mode="dark"> Dark </dt-mode-island>
Purely visual. No semantic HTML impact. Supports high contrast mode via auto contrast inheritance.
import { DtModeDirective } from '@dialpad/dialtone-vue';
app.use(DtModeDirective);
import { DtModeIsland } from '@dialpad/dialtone-vue';
Name
|
Type
|
|---|---|
default | Slot for main content |
Name
|
Default
|
Type
|
|---|---|---|
as | 'div' |
"div"
|
"section"
|
"nav"
|
"article"
|
"aside"
|
"header"
|
"footer"
|
"main"
Set this prop to render the mode island as a specific HTML element. |
mode | inverted |
"inverted"
|
"light"
|
"dark"
The mode to apply to the island. |
Mode documentation last updated Friday, September 4, 2026
fix/popover-modal-zindex-scope