On this page
frontend components
introduction
dframework ships a complete library of zero dependency, high performance custom web components compiled into the frontend bundle. components are standard custom elements with no virtual dom, no compiler requirements, and no client build step. the framework compiles and bundles component files in public/js/components/ automatically on server boot.
built in components
d-checkbox
form associated checkbox switch with synchronized label and native form submission integration.
1<d-checkbox text="enable notifications" checked name="notifications" value="1"></d-checkbox>attributes and properties
| attribute | property | type | default | form | description |
|---|---|---|---|---|---|
checked |
checked |
boolean |
false |
yes | checked state reflected in form submission |
text |
text |
string |
"checkbox" |
no | label text displayed beside the toggle |
name |
name |
string |
"" |
no | input field name used during form submission |
value |
value |
string |
"on" |
no | form submission payload sent when checked |
programmatic api
1const checkbox = select('d-checkbox');2 3// get or set checked state4checkbox.checked = true;5 6// update label text7checkbox.text = 'allow telemetry';8 9// update form payload name and value10checkbox.name = 'telemetry';11checkbox.value = 'accepted';events
| event | detail | bubbles | description |
|---|---|---|---|
change |
native event object | no | dispatched whenever the user toggles the checkbox |
behavior
- automatically synchronizes checked state, label text, and form submission values when toggled by the user or modified via javascript.
d-color-picker
high precision color picker featuring 2d saturation and brightness controls, hue slider, and alpha transparency controls.
1<d-color-picker value="#3b82f6" name="theme_color" label="accent color"></d-color-picker>attributes and properties
| attribute | property | type | default | form | description |
|---|---|---|---|---|---|
value |
value |
string |
"#d3ac5f" |
yes | current hex color value (supports 3, 4, 6, 8 digit hex) |
name |
name |
string |
"" |
no | input name attribute for form submission |
id |
id |
string |
"" |
no | element identifier |
label |
label |
string |
"color picker" |
no | header label displayed above the picker |
opened |
opened |
boolean |
false |
no | whether the popup picker panel is initially open |
programmatic api
1const picker = select('d-color-picker');2 3// toggle popup panel visibility4picker.toggle();5 6// programmatically set hex color7picker.setHex('#ef4444');8 9// read color state10console.log(picker.hex); // current hex string11console.log(picker.h, picker.s, picker.b, picker.a); // hsb and alpha valuesevents
| event | detail | bubbles | description |
|---|---|---|---|
change |
hex string | yes | dispatched when color changes via drag, input, or setHex |
input |
hex string | yes | dispatched continuously during dragging |
behavior
- interactive 2D color plane, hue bar, and alpha slider with checkered transparency.
- supports smooth dragging even outside the component bounds.
- automatically redraws on element resize and renders sharply on high resolution displays.
- clicking the reset icon restores the initial color value.
d-combobox
searchable, extensible select combobox with automatic floating placement, keyboard navigation, and dynamic option injection.
1<d-combobox[object Object]>2 placeholder="select department"[object Object]>3 allow-search[object Object]>4 allow-input[object Object]>5 name="department">6 <option value="eng" selected>engineering</option>7 <option value="des">product design</option>8 <option value="ops">operations</option>9</d-combobox>attributes and properties
| attribute | property | type | default | form | description |
|---|---|---|---|---|---|
placeholder |
placeholder |
string |
"" |
no | placeholder text displayed when no option is selected |
value |
value |
string |
null |
yes | currently selected option value |
allow-search |
allowSearch |
boolean |
false |
no | enables real time search filtering input |
allow-input |
allowInput |
boolean |
false |
no | allows adding custom options via input and plus button |
horizontal |
isHorizontal |
boolean |
false |
no | switches option layout from vertical list to horizontal chips |
name |
name |
string |
"" |
no | form field name |
id |
id |
string |
"" |
no | component id |
options |
options |
array |
[] |
no | array of {value, text, content} objects |
programmatic api
1const combo = select('d-combobox');2 3// add option dynamically4combo.addOption('mktg', 'marketing');5 6// remove option by value7combo.removeOption('ops');8 9// clear all options10combo.clearOptions();11 12// set selected value programmatically13combo.value = 'eng';14 15// close all open comboboxes across document16dCombobox.closeAll();events
| event | detail | bubbles | description |
|---|---|---|---|
change |
selected value string | yes | dispatched when an option is selected or added |
input |
selected value string | yes | dispatched when selection changes |
add |
{value, text, content} |
no | dispatched when a custom option is added |
open |
none | yes | dispatched when the dropdown panel opens |
close |
none | yes | dispatched when the dropdown panel closes |
behavior
- automatically parses child
<option>tags declared in HTML. - automatically calculates viewport space to open above or below without overflowing the screen.
- keeps floating coordinates aligned during scrolling and resizing.
- provides full keyboard navigation (arrow keys, home, end, enter, escape).
- displays an empty state indicator when search queries return no matches.
d-context-menu
contextual right click menu with automatic boundary clamping and outside click suppression.
1<div class="card p-2">2 right click inside this card3 <d-context-menu>4 <span>copy link</span>5 <span>duplicate item</span>6 <span>delete</span>7 </d-context-menu>8</div>attributes and properties
| attribute | property | type | default | form | description |
|---|---|---|---|---|---|
opened |
opened |
boolean |
false |
no | whether the context menu is open |
parent |
parent |
string |
"" |
no | selector for target parent element (defaults to parent element) |
programmatic api
1const menu = select('d-context-menu');2 3// open context menu programmatically (optionally passing pointer event for cursor positioning)4menu.open();5menu.open(pointerEvent);6 7// close context menu8menu.close();9 10// toggle context menu11menu.toggle();12 13// listen to item selection (e.detail is the clicked element)14listen(menu, 'click', (e) => {15 const target = e.target;16 const action = target.closest('[data-action]')?.getAttribute('data-action');17 if (action) handleAction(action);18});events
| event | detail | bubbles | description |
|---|---|---|---|
click |
clicked element | no | emitted through component emitter when an item is selected |
behavior
- opens on right click within its parent container and suppresses the browser default context menu.
- calculates menu dimensions and automatically bounds coordinates so the menu never overflows parent or screen edges.
- clicking outside closes the menu immediately without triggering click actions or links on underlying elements.
- automatically closes any other open context menus before opening.
- when creating dynamically in javascript, listen to
'click'directly on the component element; item wrappers are created during component mount in the next animation frame.
d-drawer
offcanvas navigation drawer with animated entrance transitions and wave styling.
1<d-drawer direction="left" id="main-drawer">2 <nav class="flex-column g-1 p-2">3 <a href="/dashboard">dashboard</a>4 <a href="/settings">settings</a>5 </nav>6</d-drawer>attributes and properties
| attribute | property | type | default | form | description |
|---|---|---|---|---|---|
opened |
opened |
boolean |
false |
no | whether the drawer is open |
direction |
direction |
string |
"left" |
no | entrance edge ("left", "right", "top", "bottom") |
programmatic api
1const drawer = select('d-drawer');2 3// open drawer (returns promise that resolves after animation completes)4await drawer.open();5 6// close drawer (returns promise)7await drawer.close();8 9// toggle drawer10await drawer.toggle();11 12// inspect animation and open state13console.log(drawer.isOpened, drawer.isAnimating);events
| event | detail | bubbles | description |
|---|---|---|---|
open |
none | yes | dispatched when the opening animation completes |
close |
none | yes | dispatched when the closing animation completes |
behavior
- slides into view from the configured edge with multi layer wave animations.
- programmatic
open(),close(), andtoggle()methods return promises that resolve upon animation completion.
d-dropdown
collapsible accordion dropdown container, perfect for faqs.
1<d-dropdown header="account security">2 <div class="p-1 flex-column g-1">3 <d-checkbox text="two factor authentication"></d-checkbox>4 <a href="/sessions" class="btn btn-sm">manage active sessions</a>5 </div>6</d-dropdown>attributes and properties
| attribute | property | type | default | form | description |
|---|---|---|---|---|---|
header |
header |
string |
"dropdown" |
no | title text displayed on the clickable header bar |
opened |
opened |
boolean |
false |
no | whether the dropdown is expanded |
programmatic api
1const dropdown = select('d-dropdown');2 3// open dropdown4dropdown.open();5 6// close dropdown7dropdown.close();8 9// toggle dropdown10dropdown.toggle();11 12// inspect open state13console.log(dropdown.isOpened);behavior
- clicking the header expands or collapses child content with an animated chevron indicator.
- dynamically updates header text and open state when properties change.
d-file-input
drag and drop file upload container with interactive item list, formatted byte size calculations, and compact bar modes.
1<d-file-input accept=".pdf,.zip,.csv" name="documents" multiple compact></d-file-input>attributes and properties
| attribute | property | type | default | form | description |
|---|---|---|---|---|---|
accept |
accept |
string |
"*/*" |
no | allowed mime types or file extensions |
icon |
icon |
string |
"dstrn-folder-line" |
no | icon class displayed in dropzone |
placeholder |
placeholder |
string |
"drag & drop file" |
no | primary dropzone title |
subtitle |
subtitle |
string |
"or click to browse" |
no | secondary helper subtitle |
compact |
compact |
boolean |
true |
no | renders as a slim horizontal bar when true |
multiple |
multiple |
boolean |
false |
no | allows selecting and dropping multiple files |
name |
name |
string |
"" |
no | form payload field name |
id |
id |
string |
"" |
no | component id |
value |
value |
object/array |
null |
yes | File, File[], or url string payload |
programmatic api
1const fileInput = select('d-file-input');2 3// reset dropzone, clearing value, file list, and native input4fileInput.reset();5 6// inspect selected files7console.log(fileInput.value); // File instance or File[] arrayevents
| event | detail | bubbles | description |
|---|---|---|---|
change |
File, File[], or null |
yes | dispatched when files are selected, dropped, or deleted |
behavior
- drag and drop file upload with file list display, formatted sizes (Bytes, KB, MB, GB), and delete buttons.
- automatically clears error states when a valid file is dropped.
- integrates with standard form submission.
d-hamburger
responsive mobile navigation hamburger trigger and full screen navigation overlay with programmable breakpoints and multi level sliding subcategory panels.
1<nav class="nav">2 <div class="container flex-row align-center justify-between py-1">3 <a d-link href="/" class="flex-row align-center">4 <img src="/img/logo.png" alt="logo">5 </a>6 7 <div id="nav-links" class="flex-row align-center g-2 md:d-flex d-none">8 <a d-link href="/features" class="nav-link">features</a>9 <div d-submenu="framework">10 <a d-link href="/architecture">architecture</a>11 <a d-link href="/benchmarks">benchmarks</a>12 </div>13 </div>14 15 <d-hamburger target="#nav-links" breakpoint="md">16 <div slot="header">17 <img src="/img/logo.png" class="logo-mark">18 </div>19 <div slot="footer">20 <d-text-input placeholder="search docs"></d-text-input>21 </div>22 </d-hamburger>23 </div>24</nav>attributes and properties
| attribute | property | type | default | form | description |
|---|---|---|---|---|---|
opened |
opened |
boolean |
false |
no | whether the overlay is open |
breakpoint |
breakpoint |
string |
"md" |
no | breakpoint token (sm, md, lg, xl, xxl, ultra) or media query |
target |
target |
string |
"" |
no | selector of desktop container to clone links from |
animation |
animation |
string |
"slide-down" |
no | overlay transition (slide-down, fade, slide-right, slide-left) |
direction |
direction |
string |
"top" |
no | entrance direction |
size |
size |
string |
"1.5em" |
no | hamburger button size in em units |
color |
color |
string |
"currentColor" |
no | button stroke color |
activecolor |
activeColor |
string |
"var(--accent)" |
no | button color when open |
autohidetarget |
autoHideTarget |
boolean |
true |
no | automatically hides desktop target container below breakpoint |
title |
title |
string |
"" |
no | fallback header title when slot="header" is omitted |
slots
slot="header": custom header content in the mobile overlay.slot="footer": custom footer content at the bottom of the overlay.
programmatic api
1const hamburger = select('d-hamburger');2 3// open overlay (returns promise)4await hamburger.open();5 6// close overlay (returns promise)7await hamburger.close();8 9// toggle overlay10await hamburger.toggle();11 12// navigate into a specific subcategory panel programmatically13hamburger.navigateTo(subPanelElement, 'framework');14 15// navigate back to previous parent panel16hamburger.navigateBack();17 18// close all open hamburger instances across the page19dHamburger.closeAll();events
| event | detail | bubbles | description |
|---|---|---|---|
open |
none | yes | dispatched when overlay opens |
close |
none | yes | dispatched when overlay closes |
behavior
- automatically displays the mobile button and hides the desktop navigation when below the specified breakpoint.
- supports nested sliding subpanels using
d-submenuattributes on link containers. - automatically manages page scroll locking while open.
- closes automatically when clicking links, pressing Escape, or navigating between pages.
d-hold-button
press and hold button that prevents accidental triggers of destructive operations by requiring a continuous pointer press.
1<d-hold-button delay="1500" class="btn btn-red" type="submit">2 hold to delete database3</d-hold-button>attributes and properties
| attribute | property | type | default | form | description |
|---|---|---|---|---|---|
delay |
delay |
number |
800 |
no | hold duration in milliseconds required before triggering action |
type |
type |
string |
"button" |
no | button type ("button", "submit") |
disabled |
disabled |
boolean |
false |
no | whether the button is disabled |
programmatic api
1const holdBtn = select('d-hold-button');2 3// adjust required hold duration in ms4holdBtn.delay = 2000;5 6// toggle disabled state7holdBtn.disabled = true;events
| event | detail | bubbles | description |
|---|---|---|---|
click |
native click event | yes | dispatched only after holding for the full delay duration |
behavior
- requires continuous press for the configured duration before triggering the click action.
- releasing before completion cancels the action and resets visual progress.
- automatically submits the surrounding form when configured with
type="submit".
d-icon-button
icon button wrapper supporting custom icons, sizes, and dynamic theme active colors.
1<d-icon-button icon="dstrn-heart-line" size="2em" color="var(--content-l)" activecolor="var(--red)"></d-icon-button>attributes and properties
| attribute | property | type | default | form | description |
|---|---|---|---|---|---|
icon |
icon |
string |
"" |
no | css icon class (e.g. dstrn-heart-line, dstrn-search) |
size |
size |
string |
"4.2em" |
no | font size of the icon container |
color |
color |
string |
"var(--content-l)" |
no | default icon color |
activecolor |
activeColor |
string |
"var(--accent)" |
no | active icon color |
id |
id |
string |
"" |
no | component id |
d-image-input
drag and drop image dropzone with instant client preview and action overlay.
1<d-image-input accept="image/png,image/jpeg" name="avatar" fit="cover" placeholder="drop profile photo"></d-image-input>attributes and properties
| attribute | property | type | default | form | description |
|---|---|---|---|---|---|
accept |
accept |
string |
"image/png, image/jpeg, image/gif" |
no | allowed image mime types |
icon |
icon |
string |
"dstrn-pic-line" |
no | placeholder icon class |
placeholder |
placeholder |
string |
"drag & drop image" |
no | dropzone title text |
subtitle |
subtitle |
string |
"or click to browse" |
no | dropzone subtitle text |
replace-text |
replaceText |
string |
"replace" |
no | text for overlay replace button |
delete-text |
deleteText |
string |
"delete" |
no | text for overlay delete button |
no-replace |
noReplace |
boolean |
false |
no | hides the replace button when true |
no-delete |
noDelete |
boolean |
false |
no | hides the delete button when true |
fit |
fit |
string |
"contain" |
no | object-fit CSS property (contain, cover, fill) |
name |
name |
string |
"" |
no | form payload field name |
id |
id |
string |
"" |
no | component id |
value |
value |
object/string |
null |
yes | File object or image URL string |
programmatic api
1const imgInput = select('d-image-input');2 3// reset dropzone and clear image preview4imgInput.reset();5 6// get or set preview src directly7imgInput.preview = '/img/avatar.png';8 9// read selected File instance10console.log(imgInput.value);events
| event | detail | bubbles | description |
|---|---|---|---|
change |
File or null |
yes | dispatched when an image is selected, dropped, or deleted |
behavior
- provides drag and drop image selection with instant preview and action buttons to replace or remove images.
- automatically integrates with form submission and clears error states on upload.
d-loader
high performance canvas arc spinner with automatic viewport intersection pause.
1<d-loader style="width: 2em; height: 2em;"></d-loader>attributes and properties
| attribute | property | type | default | form | description |
|---|---|---|---|---|---|
color |
color |
string |
"" |
no | stroke color (defaults to --accent or computed text color) |
programmatic api
1const loader = select('d-loader');2 3// destroy loader and disconnect observers4loader.destroy();behavior
- lightweight canvas spinner that automatically pauses animation when scrolled offscreen to conserve CPU.
- automatically adapts to container dimensions and renders sharply on high resolution screens.
d-modal
modal dialog container with page scroll locking and backdrop dismiss protection.
1<d-modal id="confirm-modal" persistent>2 <div class="flex-column g-1">3 <h3>confirm deletion</h3>4 <p class="text-content-l">this action cannot be undone.</p>5 <div class="flex-row justify-end g-1 mt-1">6 <button class="btn btn-sm" onclick="this.closest('d-modal').close()">cancel</button>7 <button class="btn btn-sm btn-red">delete</button>8 </div>9 </div>10</d-modal>attributes and properties
| attribute | property | type | default | form | description |
|---|---|---|---|---|---|
opened |
opened |
boolean |
false |
no | whether the modal is currently visible |
persistent |
persistent |
boolean |
false |
no | whether the element remains in the dom when closed via backdrop click |
programmatic api
1const modal = select('d-modal');2 3// open modal (locks body scroll)4modal.open();5 6// close modal (runs exit animation and unlocks body scroll)7modal.close();8 9// close, await exit transition, and remove element from dom10await modal.destroy();events
| event | detail | bubbles | description |
|---|---|---|---|
open |
none | no | dispatched when modal opens |
close |
none | no | dispatched when modal closes |
behavior and styling boundaries
- displays an overlay dialog and prevents page scrolling while visible.
- when
persistentis omitted (orfalse), clicking the backdrop closes and destroys the element (destroy()), removing it from the dom. - when
persistentis present (<d-modal persistent>), clicking the backdrop closes the dialog (close()) without removing the element from the dom, allowing it to be reopened. <d-modal>automatically injects.d-modal-wrapper(which providesvar(--container-l)background, border, radius, shadow, and padding) and.d-modal-content(flex container with scroll management).- to customize or restyle the modal appearance, target
d-modal .d-modal-wrapperord-modal .d-modal-contentin your css.
d-morph
physics based morphing animation engine (dMotion) that transitions between named elements anywhere in the document with continuous geometry, border-radius, box-shadow, and form state interpolation.
1<d-morph name="summary-card" d-action="click" d-to="detail-card" d-duration="350" d-visible>2 <div class="card p-2">3 <h4>project summary</h4>4 <p>click to expand details</p>5 </div>6</d-morph>7 8<d-morph name="detail-card" d-action="click" d-to="summary-card" d-duration="350">9 <div class="card p-4">10 <h4>detailed project view</h4>11 <p>full metadata and extended controls</p>12 </div>13</d-morph>attributes and properties
| attribute | property | type | default | description |
|---|---|---|---|---|
name |
name |
string |
"" |
unique morph identifier registered in window.dMotion |
d-visible |
none | boolean |
false |
marks this morph element as initially active and visible |
d-action |
none | string |
"" |
trigger actions: "click", "long-press", "click-out" |
d-to |
none | string |
"" |
target morph name to transition to |
d-duration |
none | number |
computed | transition duration in ms (computed from distance if omitted) |
programmatic api (window.dMotion)
1// get a morph element instance by name2const morph = dMotion.get('summary-card');3 4// get the immediately previous morph element5const prev = dMotion.getPrevious();6 7// programmatically trigger a transition between two named elements8await dMotion.transition('summary-card', 'detail-card', optionalTriggerNode);9 10// register transition lifecycle hooks ('before' or 'after')11dMotion.listen('summary-card', 'detail-card', () => {12 console.log('transition starting');13}, 'before');14 15// unregister hook16dMotion.unlisten('summary-card', 'detail-card', callback, 'before');17 18// component methods on <d-morph>19morph.show();20morph.hide();behavior
- creates smooth animated morph transitions between two elements anywhere on the page.
- preserves visual styles (size, position, border radius, shadows) and element states during animation.
- supports click, long-press, and click-out triggers.
- child elements with
d-no-morphremain interactive without triggering the transition.
d-notification
toast notification component with linear progress bar countdown and automated exit lifecycle.
1<d-notification timer="4000" opened>2 <p>project settings saved successfully</p>3</d-notification>attributes and properties
| attribute | property | type | default | form | description |
|---|---|---|---|---|---|
opened |
opened |
boolean |
false |
no | whether the toast notification is displayed |
timer |
timer |
number |
0 |
no | auto dismissal duration in milliseconds (0 disables timer) |
programmatic api
1const toast = select('d-notification');2 3// show toast and start progress bar countdown4toast.show();5 6// hide toast7toast.hide();8 9// hide, wait for animation to finish, and remove from dom10await toast.destroy();behavior
- displays toast notifications with an optional countdown progress bar that automatically dismisses after the timer expires.
d-skeleton
content loading placeholder shapes with customizable dimensions, line counts, and card presets.
1<d-skeleton type="text" lines="3" gap="0.5em"></d-skeleton>2<d-skeleton type="circle" size="3em"></d-skeleton>3<d-skeleton type="rect" width="100%" height="150px" radius="0.5em"></d-skeleton>4<d-skeleton type="card"></d-skeleton>attributes and properties
| attribute | property | type | default | description |
|---|---|---|---|---|
type |
type |
string |
"text" |
preset shape ("text", "circle", "rect", "card") |
lines |
lines |
number |
1 |
line count for "text" type (last line renders at 60% width) |
width |
width |
string |
null |
CSS width |
height |
height |
string |
null |
CSS height |
size |
size |
string |
null |
shorthand for equal width and height on circle and rect |
gap |
gap |
string |
"0.6em" |
vertical gap between lines in text mode |
radius |
radius |
string |
null |
custom border-radius override |
d-slider
range slider with pointer dragging, keyboard navigation, audio feedback, and automatic indicator text binding.
1<d-slider id="volume" name="volume" min="0" max="1" step="0.01" value="0.75"></d-slider>2<span data-slider-volume class="text-content-l">75%</span>attributes and properties
| attribute | property | type | default | form | description |
|---|---|---|---|---|---|
value |
value |
number |
0.5 |
yes | current numeric slider value |
min |
min |
number |
0 |
no | minimum allowable value |
max |
max |
number |
1 |
no | maximum allowable value |
step |
step |
number |
0.01 |
no | step increment for dragging and arrow keys |
name |
name |
string |
"" |
no | form payload field name |
id |
id |
string |
"" |
no | component id (used for data-slider-{id} text binding) |
disabled |
disabled |
boolean |
false |
no | disables slider interactions |
thumbcolor |
thumbColor |
string |
"var(--accent)" |
no | thumb color variable |
fillcolor |
fillColor |
string |
"var(--accent-d)" |
no | active track fill color variable |
trackcolor |
trackColor |
string |
"var(--border-muted)" |
no | inactive track background color variable |
sfx |
none | string |
embedded | no | audio sound effect URL or base64 audio payload |
programmatic api
1const slider = select('d-slider');2 3// read current value4const current = slider.getValue();5 6// set new value (updates visual fill, thumb position, and data-slider indicator)7slider.setValue(0.85);events
| event | detail | bubbles | description |
|---|---|---|---|
input |
numeric value | yes | dispatched during continuous dragging and arrow key movement |
change |
numeric value | yes | dispatched on pointer up or keyboard commit |
behavior
- supports smooth dragging and keyboard arrow navigation.
- automatically updates text in any element with
data-slider-{id}with the current percentage value. - integrates with form submission.
d-text-input
enhanced input field with icon prefixes, keyboard shortcut binding, number stepper buttons, and form integration.
1<d-text-input[object Object]>2 placeholder="search records"[object Object]>3 icon="dstrn-search-line"[object Object]>4 shortcut="cmd+k"[object Object]>5 name="query">6</d-text-input>attributes and properties
| attribute | property | type | default | form | description |
|---|---|---|---|---|---|
placeholder |
placeholder |
string |
"" |
no | placeholder text |
icon |
icon |
string |
"" |
no | icon class name |
type |
type |
string |
"text" |
no | input type ("text", "password", "search", "number") |
autocomplete |
autocomplete |
boolean |
false |
no | browser autocomplete flag |
value |
value |
string |
"" |
yes | current input string value |
name |
name |
string |
"" |
no | form field name |
id |
id |
string |
"" |
no | component id |
shortcut |
shortcut |
string |
"" |
no | global keyboard shortcut (e.g. "cmd+k", "ctrl+f") |
disabled |
disabled |
boolean |
false |
no | disables input |
readonly |
readonly |
boolean |
false |
no | sets input to read only mode |
min |
min |
string |
"" |
no | minimum number value |
max |
max |
string |
"" |
no | maximum number value |
step |
step |
string |
"1" |
no | step value for number controls |
programmatic api
1const input = select('d-text-input');2 3// update value4input.value = 'search term';5 6// read or modify properties7input.placeholder = 'type command';8input.disabled = false;events
| event | detail | bubbles | description |
|---|---|---|---|
change |
string value | yes | dispatched on input modification |
behavior
- supports global keyboard shortcuts (e.g.
cmd+k) that focus the field automatically across operating systems. - displays increment and decrement stepper controls when configured with
type="number".
d-toggle
segmented toggle control with magnetic hover indicators and animated transitions.
1<d-toggle name="billing_period" value="0">2 <div default>monthly billing</div>3 <div>annual billing (save 20%)</div>4</d-toggle>attributes and properties
| attribute | property | type | default | form | description |
|---|---|---|---|---|---|
value |
value |
number |
0 |
yes | zero indexed integer of currently selected option |
name |
name |
string |
"" |
no | form field name |
id |
id |
string |
"" |
no | component id |
color |
color |
string |
"var(--container-l)" |
no | container background color variable |
activecolor |
activeColor |
string |
"var(--accent)" |
no | active option highlight color |
textcolor |
textColor |
string |
"var(--content-l)" |
no | inactive option text color |
textactivecolor |
textActiveColor |
string |
"" |
no | active option text color |
bgcolor |
bgColor |
string |
"var(--container-l)" |
no | base background color |
hovercolor |
hoverColor |
string |
"rgba(255, 255, 255, 0.05)" |
no | hover background color |
programmatic api
1const toggle = select('d-toggle');2 3// get currently active button element4console.log(toggle.selected);5 6// activate option by index (number), string index, or button element7toggle.selected = 1;8 9// read or set numeric value10toggle.value = 0;events
| event | detail | bubbles | description |
|---|---|---|---|
change |
selected index number | yes | dispatched when active selection changes |
behavior
- renders interactive segmented options with animated hover and selection transitions.
- supports initial selection via the
defaultattribute or numeric value.
overriding built in components
every built in component behavior can be customized, extended, or completely overwritten by application code. to override a built in component, place a file with the exact same component filename under public/js/components/ (such as public/js/components/dCheckbox.js).
when compiling the frontend bundle, the compiler automatically detects the user file and replaces the built in component implementation in place.
1// public/js/components/dCheckbox.js2class dCheckbox extends dComponent {3 static form = true;4 static get tag() { return 'd-checkbox'; }5 6 // custom template or methods7}8 9dComponent.define(dCheckbox);
immutable base class
all custom elements and overrides extend dComponent. unlike UI components, dComponent is the immutable framework base class providing reactivity, reflection, and lifecycle management. the compiler always preserves the core dComponent implementation at the root of the bundle so all components inherit from it consistently.
dComponent (base class)
dComponent is the authoring base class for all custom web components in dframework. it provides property reflection, reactive proxy state, form integration, surgical dom rendering, and automatic memory cleanup.
1class dCounter extends dComponent {2 static tag = 'd-counter';3 static form = true; // opt into native form submission integration4 5 static props = {6 value: { type: 'number', default: 0, form: true },7 step: { type: 'number', default: 1 },8 disabled: { type: 'boolean', default: false },9 label: { type: 'string', default: 'count' }10 };11 12 template() {13 // called once on mount to establish initial innerHTML14 return `[object Object]>15 <span class="label">${this.label}</span>[object Object]>16 <button class="dec" type="button">−</button>[object Object]>17 <span class="value">${this.value}</span>[object Object]>18 <button class="inc" type="button">+</button>[object Object]>19 `;20 }21 22 mount() {23 // called once after template initialization24 this.effect(() => {25 // reading this.state or props registers auto dependencies26 document.title = `count: ${this.state.value ?? this.value}`;27 return () => { document.title = 'app'; }; // optional cleanup28 });29 }30 31 render() {32 // called automatically on prop or state changes33 // use for surgical dom updates only (never mutate this.state here)34 this.refs('.value')[0].textContent = this.state.value ?? this.value;35 this.refs('button.dec')[0].disabled = this.disabled;36 this.refs('button.inc')[0].disabled = this.disabled;37 38 // listeners attached inside render() are cleared and rebound automatically39 this.listen(this.refs('button.dec')[0], 'click', () => this.decrement());40 this.listen(this.refs('button.inc')[0], 'click', () => this.increment());41 }42 43 onPropChanged(name, oldVal, newVal) {44 // called on attribute or property modifications45 }46 47 increment() {48 this.setState(s => { s.value = (s.value ?? this.value) + this.step; });49 }50 51 decrement() {52 this.setState(s => { s.value = (s.value ?? this.value) - this.step; });53 }54}55 56dComponent.define(dCounter);
component definition and registration
register components using dComponent.define(Class):
1dComponent.define(dCounter);- automatically defines getter and setter properties on the prototype with type coercion (
number,boolean,string,object,array). - binds observed attributes to property setters.
- registers with
customElements.defineusingClass.tag.
lifecycle methods
| method | timing | description |
|---|---|---|
template() |
before mount | returns initial HTML string to populate inner dom |
mount() |
on first connection | initializes component logic and registers effects |
connected() |
on every connection | called whenever element is attached to document |
render() |
on state/prop change | performs surgical dom node updates |
onPropChanged(name, old, new) |
on prop mutation | reacts to specific property changes |
destroy() |
on disconnection | teardown hook called when element is removed from dom |
`mount()` initialization is batched via `requestAnimationFrame` upon initial dom connection. this guarantees that all child nodes parsed in the light dom are present and available before `mount()` executes. for template components, template markup is preparsed on definition and stamped via cached `cloneNode(true)`. subsequent property and state updates are batched into a static 3 phase microtask flush.
fragment caching and batch mounting
for maximum throughput when generating dynamic content or lists of components, dComponent provides static utilities backed by an internal template lru cache:
1// parse html into a cached template fragment (avoids repeated innerHTML string parsing)2const frag = dComponent.fragment('<div class="list-item"><span>title</span></div>');3 4// append multiple nodes, fragments, or html strings in a single dom operation5dComponent.appendMany(container, frag1, frag2, '<div class="extra">item</div>');
rendering strategy and surgical updates
dComponent avoids virtual dom overhead. dom nodes are created once in template() or mount(), while dynamic updates are applied surgically inside render().
`this.state` must never be modified inside `render()`. state mutations inside `render()` are blocked to prevent infinite update loops.
batched microtask update queue
property modifications and state mutations are automatically coalesced across all active components into a static 3 phase microtask flush:
- phase 1 (attribute sync): synchronizes observed html attributes for changed properties.
- phase 2 (rendering): clears transient render listeners and executes
render()once per updated component. - phase 3 (effects & form sync): reevaluates reactive effects, invalidates refs caches, synchronizes form internals, and dispatches an aggregated debugbar event.
1// multiple synchronous state mutations trigger exactly one render cycle in the next microtask2this.state.title = 'new title';3this.state.count = 42;
reactive state
1// update state and trigger microtask batched render()2this.setState({ active: true });3 4// functional updater5this.setState(s => { s.count++; s.updatedAt = Date.now(); });6 7// update state without triggering render() (still triggers effect loops)8this.setState({ timer: Date.now() }, false);
effects and dependency tracking
1// auto tracking effect (tracks any accessed this.state or prop)2this.effect(() => {3 console.log('value updated:', this.state.value);4 return () => console.log('cleaning up effect');5});6 7// explicit dependency array effect8this.effect(() => {9 fetchData(this.query);10}, () => [this.query]);
automatic cleanup apis
these methods automatically clean up listeners, timers, and animation frame requests when the component is removed from the dom:
1// event listener with auto cleanup2this.listen(element, 'click', (e) => this.handleClick(e));3 4// listen to multiple elements5this.listenAll(elements, 'click', (e) => this.handleClick(e));6 7// unlisten manually if needed8this.unlisten(element, 'click', handler);9 10// auto cleared timers11this.setTimeout(() => this.tick(), 1000);12this.setInterval(() => this.refresh(), 5000);13 14// auto cleared animation frame15this.requestAnimationFrame((time) => this.draw(time));
dom caching and refs
this.refs(selector) caches queried element arrays between renders to eliminate repeated dom query overhead:
1const [inputEl] = this.refs('input.search');
inner content capture
access original light dom nodes passed into the custom element before template() execution:
1this.originalChildren // array of cloned child nodes2this.originalHTML // original innerHTML string3this.cloneChildren() // returns fresh clones of original child nodes
form integration
when static form = true, dComponent integrates with parent <form> elements and submits properties marked with form: true:
1static form = true;2static props = {3 value: { type: 'string', default: '', form: true }4};5 6// access parent form element7console.log(this.form);supports single values, file instances (File), file arrays (File[]), and multiple form properties automatically.
internal event emitter
1// listen to component events2this.on('custom-event', (data) => console.log(data));3 4// remove listener5this.off('custom-event', handler);6 7// emit event to internal listeners8this.emit('custom-event', { id: 123 });
websocket integration
1// emit event through global websocket connection2this.wire('chat:send', { message: 'hello' });
