Component reference
The dd-* elements with their attributes, parts, slots, presets, and override points.
The house style ships as Web Components: custom elements that come
pre-styled from the design tokens and react to theme changes for free.
Nothing to import; linking the SDK registers every dd-* element for the
document.
Each element renders into a Shadow DOM, styled by the same shared stylesheet
raw-class widgets use, so a theme change (which rewrites the --dd-* tokens
on :root) restyles component internals automatically. Your own CSS cannot
reach inside with ordinary selectors; use the exposed hooks instead:
::part(name), the documented custom-property knobs, and named slots.
Unless a component says otherwise, it is presentational: clicks bubble from the host element and you wire them yourself; nothing acts on its own.
dd-text
Typography. Content is projected; the host carries the font and color.
<dd-text variant="title">Tasks</dd-text>
<dd-text variant="muted">3 open</dd-text>
<dd-text size="xl" weight="bold">42</dd-text>variant picks a semantic default (size, weight, color):
| variant | Use |
|---|---|
body (default) | plain body text |
title | panel or section heading (semibold, large, display face) |
subtitle | secondary heading (muted, medium) |
label | uppercase tracked label |
muted | secondary or status text |
value | big readout (semibold, tabular, display face; add mono for metrics) |
size (xs to 2xl), weight (normal, medium, semibold, bold)
and the boolean mono override or extend the variant; they map straight
onto the type scale tokens. The
attribute values are the complete vocabulary: anything else does nothing.
For a truly special size, put a plain font-size on the element; an id or
class selector beats the variant default.
dd-icon
<dd-icon name="plus"></dd-icon> <!-- built-in glyph, tinted -->
<dd-icon src="icons/rain.svg"></dd-icon> <!-- your SVG, full color -->
<dd-icon src="icons/rain.svg" tint></dd-icon> <!-- your SVG, masked to the text color -->namepicks a built-in glyph, drawn as a currentColor mask so it follows the text color and themes. The full set:battery,check,chevron-down,close,gear,lock,pause,play,plus,power,refresh,search,sign-out,skip-back,skip-forward,sleep,volume,volume-mute,wifi. Names are validated (lowercase, digits, hyphens); anything else is ignored.srcrenders an SVG file from your widget folder (or adata:URI) as a real image, so the SVG's own colors show. Addtintto mask it in the current text color instead. The image carries partimg.
Size via --dd-icon-size (default 1.25em). Swap at runtime with
icon.setAttribute("src", ...) or bind it:
create("dd-icon", { src: () => ... }).
There is no external-sprite mode (one file, many icons by name); ship one
SVG per icon, or build stateful art inline with dd.ui.create.
dd-panel
The bordered card that fills the widget and stacks its children.
<dd-panel heading="Weather" settings="panelStyle">
<button slot="actions" class="dd-icon-btn">...</button>
<div class="dd-scroll">...</div>
</dd-panel>| Attribute | Effect |
|---|---|
heading="..." | render a title row. Use heading, not title (the native tooltip) |
transparent | glassy surface instead of solid |
bare | no paint at all: the card keeps its box (padding, layout) but drops background and border |
row | lay children horizontally |
settings="panelStyle" | auto-wire the panel-style preset (see below) |
| Slot | For |
|---|---|
| (default) | the panel body |
heading | a custom or dynamic heading, instead of the attribute |
actions | controls pinned to the right of the header |
| Part | For |
|---|---|
surface | the card itself (override padding, layout, border) |
header | the heading row |
heading | the heading text |
Knob: --dd-panel-pad sets the surface padding (default
var(--dd-space-3) var(--dd-space-4)). The header row renders only when
there is a heading attribute or slotted heading/actions content; an
empty header hides itself.
/* the surface lives in the shadow, so reach it via the part */
#panel::part(surface) { flex-direction: row; gap: 4vw; padding: 0; }dd-button
The standard button. variant is solid (default), ghost, or outline;
content (a label, a dd-icon) is projected; disabled blocks it. Part:
button.
<dd-button>Save</dd-button>
<dd-button variant="ghost">Clear done</dd-button>
<dd-button variant="outline">Connect</dd-button>btn.addEventListener("click", () => { /* ... */ }); // host click bubbles out
btn.setAttribute("disabled", ""); // reflects onto the inner buttondd-icon-button
The square (or round circle) icon button: transparent at rest, surface on
hover. The glyph comes from name (a built-in glyph) or the slot (a
dd-icon, or custom SVG built with dd.ui.create). Boolean attributes:
round, active (accent border and text), off (muted), disabled.
Part: button.
<dd-icon-button name="plus" title="Add"></dd-icon-button>
<dd-icon-button round name="play" title="Play"></dd-icon-button>
<dd-icon-button round><dd-icon name="chevron-down"></dd-icon></dd-icon-button>/* stateful toggle: swap the built-in glyph by name */
playBtn.setAttribute("name", playing ? "pause" : "play");dd-meter
The horizontal track-and-fill meter. value is 0..100 (clamped).
severity (success, warning, danger) swaps the fill to the matching
status token; without it the fill is --dd-meter-color (default: the
accent), so a widget can inject a resolved custom color. Height via
--dd-meter-height (default 0.4em, so it rides the surrounding font
size). Parts: track, fill.
<dd-meter value="63"></dd-meter>
<dd-meter value="97" severity="danger"></dd-meter>meter.setAttribute("value", String(pct));
meter.style.setProperty("--dd-meter-color", resolvedAccent);dd-chip
A pill toggle. Boolean attributes: dim (low emphasis), active (accent
border and text), disabled. Content is projected. Part: chip.
<dd-chip dim>Other networks...</dd-chip>
<dd-chip active>On</dd-chip>/* an app-specific state, via the part */
dd-chip.is-hidden::part(chip) { text-decoration: line-through; }dd-app-tile
A launcher tile: an icon (or a letter fallback) with an optional label.
<dd-app-tile src="icons/steam.png" label="Steam"></dd-app-tile>
<dd-app-tile glyph="S" label="Steam"></dd-app-tile>
<dd-app-tile add label="Add"></dd-app-tile>| Attribute | Effect |
|---|---|
src="..." | an image icon (full color) |
glyph="A" | a letter or emoji fallback when there is no image |
add | the dashed plus affordance (ignores src and glyph) |
label="..." | caption under (or beside) the icon; omit for icon-only |
orientation="row" | lay icon and label horizontally |
disabled | block the click |
Parts: tile (the button surface), icon (the icon box), label. Size the
host from your own CSS; the icon box follows --dd-tile-icon (default
2em).
tile.addEventListener("click", () => dd.apps.launch(app.id));
dd.peers.draggable(tile, { /* ... */ }); // binds to the host finedd-app-tile { width: 56px; height: 56px; --dd-tile-icon: 32px; }
dd-app-tile::part(label) { color: var(--dd-text-muted); }dd-volume-pill
Mute button, slider, percent readout, and a sound-settings shortcut in one
element. The one behavior-ful component: it subscribes to the vitals stream
and drives the system volume itself, so the manifest must grant system
and systemControls. Failed calls log a warning and the pill stays up.
Built for popout pane documents, but works anywhere.
no-settingshides the settings gear.- Parts:
pill,slider,value. The mute and gear buttons expose no parts. - Slider input is throttled internally to roughly 10 volume calls per second, and the thumb and percent hold still during a drag.
- Event
dragchange(bubbling, composed,detail: { dragging }) fires as the user grabs and releases the slider. A pane document should relay it so the base widget's flyout helper holds its hover-retract during a drag:
pill.addEventListener("dragchange", (e) => dd.popout.send(e.detail));Settings presets on components
The settings attribute wires a component to a
setting preset by name, and
accepts a comma-separated list. <dd-panel settings="panelStyle"> observes
the panel setting and toggles its own transparent/bare attributes,
with zero widget code. Reading settings needs no permission, and presets
never write settings.
Two notes: the wiring happens once, when the element first connects
(changing the attribute later does nothing), and accentColor is a
fields-only preset with no component-side behavior; read it with
dd.theme.accent() instead
of putting it in a settings attribute.
Overriding
Two tiers, matching how much you want to change:
- Style hooks.
::part(), the custom-property knobs, and named slots, as documented per component above. - Subclass and call super. The constructors are exposed on
dd.ui.components(DdElement,DdPanel,DdText,DdIcon,DdButton,DdIconButton,DdChip,DdMeter,DdAppTile,DdVolumePill). Extend one, override a method (build,render,applyPreset), call the super method to keep the original behavior or skip it to replace it, then register your own tag:
class MyPanel extends dd.ui.components.DdPanel {
render() {
super.render(); // keep the panel's own logic...
this.surface.classList.toggle("my-flag", flag); // ...and add to it
}
}
customElements.define("my-panel", MyPanel);Building the rest
Components cover chrome. Build everything else with
dd.ui.create; components compose with
it and with each other (a dd-panel heading is itself a dd-text).