v0.21

frontend utilities

introduction

dframework ships a complete utility layer for styling and dom interaction. utility classes are generated at compile time. no runtime css in js. frontend functions are available globally in every page script and component.

button classes

you can use prestyled buttons by using the base class btn and then chaining a prefix class btn-* where * represents the button color.

available colors description
.btn-accent accent colored button
.btn-red soft red button
.btn-yellow soft yellow button
.btn-green soft green button
.btn-blue soft blue button
.btn-purple soft purple button
.btn-pink soft pink button
.btn-gray var(--container) colored button
.btn-transparent transparent button (use for animation)

responsive prefixes

any utility class can be prefixed with a viewport breakpoint. prefixed classes apply only when the viewport meets or exceeds the defined width.

prefix min-width
sm: 480px
md: 768px
lg: 1024px
xl: 1280px
xxl: 1536px
ultra: 1920px
1<div class="flex-column md:flex-row g-1 md:g-2">...</div>

layout

positioning

class description
.relative position: relative
.fixed position: fixed
.sticky position: sticky
.absolute position: absolute
.absolute-center absolute center via translate
.absolute-x-center absolute horizontal center
.absolute-y-center absolute vertical center
.absolute-fill fill parent element absolutely
.top-0 / .bottom-0 top: 0 / bottom: 0
.left-0 / .right-0 left: 0 / right: 0
.top-50 / .bottom-50 top: 50% / bottom: 50%
.left-50 / .right-50 left: 50% / right: 50%
.top-[1–10] top in em steps
.bottom-[1–10] bottom in em steps
.left-[1–10] left in em steps
.right-[1–10] right in em steps
.inset-0 top/right/bottom/left: 0 (no position set)
.z-[0–auto] z-index: 0, 1, 2, 3, 4, 5, 10, 50, 100, auto

grid

class description
.grid-center centered grid
.grid-2 2-column grid
.grid-3 3-column grid
.grid-4 4-column grid
.grid-auto dense auto-flow grid
.col-span-[1–4,full] grid column span
.row-span-[1-3,full] grid row span
.col-start-[1–4] grid column start
.col-end-[1–4] grid column end
.row-start-[1–3] grid row start
.row-end-[1–3] grid row end

flexbox

class description
.flex-row flex-direction: row
.flex-column flex-direction: column
.flex-center center on both axes
.flex-wrap flex-wrap: wrap
.flex-1 flex: 1 1 0%
.flex-auto flex: 1 1 auto
.flex-none flex: none
.grow / .grow-0 individual flex-grow control
.shrink / .shrink-0 individual flex-shrink control
.order-[1–5] / `.order-[first last
`.justify-[start end
`.align-[start end
`.self-[start end

spacing

values available for all spacing classes: 0, 025, 05, 075, 1, 125, 15, 175, 2 through 10 (integer steps). margin also accepts auto.

prefix applies to
.p- all padding
.px- horizontal padding
.py- vertical padding
.pt- / .pb- top / bottom padding
.pl- / .pr- left / right padding
.m- all margin
.mx- horizontal margin
.my- vertical margin
.mt- / .mb- top / bottom margin
.ml- / .mr- left / right margin
.g- gap (both axes)
.gx- column gap only
.gy- row gap only

sizing

prefix values
.w- 100vw, 5100 (5 step), auto, min, max, fit
.h- 100svh, 5100 (5 step), auto, min, max, fit
.min-w- / .max-w- same as .w-
.min-h- / .max-h- same as .h-

typography

class description
.fs-[01–10] font-size from .1em to 10em in .1em steps
.fw-[100–900] font-weight in hundreds (100 = thin, 900 = black)
.thin font-weight: 300
.bold font-weight: 700
.uppercase / .lowercase / .capitalize text-transform
.italic / .not-italic font-style control
`.text-[left center
.text-vertical vertical writing mode
.lh-[1–3] line height (1, 1.1, 1.15, 1.2, 1.25, … , 3)
.underline / .line-through / .no-underline text decoration
`.decoration-[dotted dashed
`.underline-offset-[1 2]`
.truncate truncate with ellipsis (alias)
.overflow-ellipsis truncate with ellipsis
.line-clamp-[1–4] clamp to N lines with ellipsis
.indent-[1–3] text-indent in em
`.whitespace-[pre pre-wrap
.break-words / .break-all / .break-keep word-breaking

appearance

class description
.bdr-[0–2] border-radius in .1em steps
.bdr-circle border-radius: 50%
`.border-[s m
`.border-[top bottom
.bg-[color] background (container, accent, red, blue, green, …)
.text-[color] text color (same values)
`.shadow-[s m
.opacity-[0–1] opacity (0, .1, .2 … 1)
.invert filter: invert(1)
.grayscale / .grayscale-0 full / remove grayscale filter
`.blur-[sm md
`.brightness-[50 75
`.contrast-[50 75
`.saturate-[0 50
.sepia sepia filter
`.hue-rotate-[15 30
.filter-none remove all filters
`.backdrop-blur-[sm md
`.object-[cover contain
`.object-[center top
.visible / .invisible visibility (preserves layout space)
.list-none / .list-disc / .list-decimal list style type
.list-inside / .list-outside list style position
.divide-y / .divide-x border between children
.table styled table (header, rows, hover)
.table-bordered .table variant with borders
.table-striped .table variant with alternating rows
.table-compact .table variant with compact padding
.table-auto / .table-fixed table layout mode
.border-collapse / .border-separate border collapse mode
.border-spacing-0 remove border-spacing
.table-caption table caption styling
.outline-none outline: none

interaction

class description
.pointer cursor: pointer
.no-events pointer-events: none
`.click-haptic-[small med]`
.hover:bg-[color] background change on hover
.hover:text-[color] text color change on hover
.shadow-hover-[s,m,l] shadow change on hover
.select-none / .select-text / .select-all user-select control
.appearance-none remove native form styling
.sr-only visually hidden but accessible
.float-left / .float-right / .float-none float
.clear-both / .clear-left / .clear-right / .clear-none clear
.align-top / .align-middle / .align-bottom vertical-align
.align-text-top / .align-text-bottom vertical-align (text-relative)
.align-sub / .align-super vertical-align for sub/superscript

transitions & animation

class description
.tr-[01–1] transition duration from .1s to 1s
.fade-[in,out] opacity transition
.slide-in-[left,right,up,down] entry movement
.slide-out-[left,right,up,down] exit movement
.preload disables all transitions

performance

these classes communicate rendering hints to the browser. apply them to elements with complex, frequently updated content.

class description
.stable will-change: transform; contain: paint
.self-contained contain: layout paint
.isolated contain: strict
.gpu transform: translateZ(0); will-change: transform, opacity

dom functions

global functions available in all page scripts and components. these should be preferred over native browser apis. they return cleanup functions and integrate with dComponent's auto cleanup system.

selection

1select('.btn-primary') // querySelector shorthand
2selectAll('.card') // querySelectorAll, returns a true array
3select('.input', formElement) // scoped to a parent element

events

1const cleanup = listen(button, 'click', handler);
2cleanup(); // detach manually if needed
3
4listenAll(selectAll('.btn'), 'click', handler);

classes

1addClass('active', el)
2removeClass('hidden', el)
3toggleClass('open', el, state) // state is optional
4hasClass('disabled', el) // returns boolean

fragments and mounting

1// parse html into a cached template fragment
2const frag = createFragment('<div class="card"><span>title</span></div>');
3
4// batch append multiple nodes, fragments, or html strings in a single dom operation
5appendMany(container, frag, '<div class="item">text</div>', customNode);

timing

1await nextFrame(); // resolves after 2 raf cycles (safe for measuring after dom changes)
2await sleep(300); // promise based delay

data functions

escaping

1escapeHtml(v) // escapes html entities (&, <, >, ", ')
2escapeJs(v) // escapes quotes, backticks, backslashes, dollar signs, control chars, and </script> tags

type checking

1isString(v) isNumber(v) isBoolean(v)
2isArray(v) isObject(v) isFunction(v)
3isEmpty(v) // true for "", [], {}, null, undefined
4hasValue(v) // true if not empty, null, or undefined

array utilities

1move(input, from, to) // move an item within an array or string
2remove(input, index) // remove an item at index
3replace(input, index, val) // replace an item at index
4limit(input, max) // slice to a maximum length
5uniquify(input) // remove duplicates from an array or string
6
7asyncForEach(arr, fn) // serial async iteration (awaits each fn before continuing)

extras

1random(1, 100) // inclusive integer random
2uniqueId(8) // collision resistant unique id string
3clipboard('text to copy') // write to system clipboard
4formatTime(seconds) // returns "mm:ss"
5formatDate(date, false) // returns "YYYY-MM-DD"
6formatDate(date) // returns "YYYY-MM-DD HH:mm:ss"
7localizeDate(date, false) // returns "YYYY-MM-DD" in the user's timezone
8localizeDate(date) // returns "YYYY-MM-DD HH:mm:ss" in the user's timezone
9distance(a, b) // levenshtein or jaccard distance between two strings
10
11Storage.get('key') // typed localStorage wrapper
12Storage.set('key', value)
13Storage.remove('key')
14Storage.clear()

notify & modal

notify

displays a non blocking toast notification. auto dismisses after the timer expires.

1notify('profile updated');
2notify('upload failed — please try again', 6000); // custom duration in ms

pass a setup callback to attach interaction to notification elements. use .listen() inside the callback for automatic cleanup when the notification closes:

1notify('<button class="undo-btn">undo</button>', 5000, (n) => {
2 n.listen(n.querySelector('.undo-btn'), 'click', () => {
3 undoLastAction();
4 n.close();
5 });
6});
7
8// omit the timer to control close timing from the callback
9notify('<button class="undo-btn">undo</button>', (n) => {
10 n.listen(n.querySelector('.undo-btn'), 'click', () => n.close());
11});

displays a floating modal. handles its opening animation and removes itself from the dom after closing.

1modal('<h2>success</h2><p>your order has been placed.</p>');

pass a setup callback for interactive modals. use .listen() for automatic cleanup:

1modal(`
2 <h2>delete post</h2>
3 <p>this action cannot be undone.</p>
4 <button class="btn-danger confirm">delete</button>
5 <button class="btn cancel">cancel</button>
6`, (m) => {
7 m.listen(m.querySelector('.confirm'), 'click', async () => {
8 await fetch(`/posts/${postId}`, { method: 'DELETE' });
9 m.close();
10 notify('post deleted');
11 });
12
13 m.listen(m.querySelector('.cancel'), 'click', () => m.close());
14});