Reference

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):

variantUse
body (default)plain body text
titlepanel or section heading (semibold, large, display face)
subtitlesecondary heading (muted, medium)
labeluppercase tracked label
mutedsecondary or status text
valuebig 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 -->
  • name picks 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.
  • src renders an SVG file from your widget folder (or a data: URI) as a real image, so the SVG's own colors show. Add tint to mask it in the current text color instead. The image carries part img.

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>
AttributeEffect
heading="..."render a title row. Use heading, not title (the native tooltip)
transparentglassy surface instead of solid
bareno paint at all: the card keeps its box (padding, layout) but drops background and border
rowlay children horizontally
settings="panelStyle"auto-wire the panel-style preset (see below)
SlotFor
(default)the panel body
headinga custom or dynamic heading, instead of the attribute
actionscontrols pinned to the right of the header
PartFor
surfacethe card itself (override padding, layout, border)
headerthe heading row
headingthe 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 button

dd-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>
AttributeEffect
src="..."an image icon (full color)
glyph="A"a letter or emoji fallback when there is no image
addthe 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
disabledblock 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 fine
dd-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-settings hides 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).