@hyperfrontend/ui-utils§

Two panels of counters over six mount and unmount cycles: on the left, red bars for style elements, ResizeObservers and listeners climb to six and stay there; on the right, the same three counters in green rise and drop back to zero every cycleTwo panels of counters over six mount and unmount cycles: on the left, red bars for style elements, ResizeObservers and listeners climb to six and stay there; on the right, the same three counters in green rise and drop back to zero every cycle

Modular DOM utilities for dynamic styling, gesture detection, element lifecycle, and color manipulation.

What is @hyperfrontend/ui-utils?

Sometimes a framework is not on the table. You are writing an embed that drops into someone else's page, a debug overlay, a script tag, a canvas experiment: something where React would be more runtime than the thing it wraps. So you are back to document.createElement and appendChild, a <style> tag you have to remember to remove, and a ResizeObserver you have to remember to disconnect. This package is that pile of chores, written once and tested.

The parts worth the install:

  • createElement gives you the node plus attach, detach, show, and hide, with an opacity transition when you pass a duration.
  • addStylesheet injects real CSS and hands back the function that removes it, so your rules leave when your widget does.
  • syncElementDimensions pins an overlay to an element you do not control and keeps it there through resizes.
  • getElementAsync polls for a node that has not rendered yet and returns a cancel function.
  • createGestureListener covers Escape and pinch-out with one cleanup.
  • setupAudio waits for the click or touch that browsers require before an AudioContext will start.

Anything that attaches something gives you back the function that detaches it.

At a glance:

import { createElement, syncElementDimensions } from '@hyperfrontend/ui-utils/element'
import { addStylesheet } from '@hyperfrontend/ui-utils/style'

const [, removeStyles] = addStylesheet(
  {
    '.hf-hint': { position: 'fixed', opacity: '0', outline: '2px solid #f0f' },
  },
  'hf-hint'
)

const hint = createElement('div', { className: 'hf-hint' })
hint.attachTo(document.body)
hint.show(150) // opacity transition over 150ms

// follow a node you do not own, through every resize
const stopTracking = syncElementDimensions('#third-party-widget', hint.ref)

// teardown leaves the page as you found it
stopTracking()
hint.detachFromParent()
removeStyles()

Key Features

Why Use @hyperfrontend/ui-utils?

A framework is not always an option

Embeds on someone else's page, browser extensions, tooling panels, canvas demos, snippets that ship as one script tag: places where you cannot mount a component tree, or would rather not pay for one. These are plain functions over plain DOM nodes, so they run under any framework or none, and they do not care what rendered the page around them.

The cleanup is the point

Overlay code leaks in predictable ways: a stylesheet that outlives the widget it styled, an observer nobody disconnected, a poll still running long after the element showed up. Every function here that attaches something returns the thing that removes it, so teardown is a short list of calls you already have instead of a hunt through the document.

Following elements you do not control

syncElementDimensions takes a source and a target, copies width, height, top, left, and position from one to the other, and repeats that on every resize of the source. Both arguments accept a selector, so the source can be a node that has not rendered yet: getElementAsync polls for it every 100ms and gives up after 10 seconds by default, and the cleanup function cancels the poll if you gave up first.

Import one corner, not the package

Every capability is its own entry point, so import { hexToRgb } from '@hyperfrontend/ui-utils/color' pulls in the color conversions and nothing else. That matters when the whole budget for an embed is a few kilobytes.

Installation

npm install @hyperfrontend/ui-utils

Quick Start

// Element creation with lifecycle methods
import { createElement } from '@hyperfrontend/ui-utils/element'

const modal = createElement('div', {
  className: 'modal',
  inlineStyle: { position: 'fixed', zIndex: '1000' },
})

modal.attachTo(document.body)
modal.show(300) // Fade in over 300ms
modal.hide(300) // Fade out over 300ms
modal.detachFromParent() // Clean removal

// Type-safe CSS selector building
import { CssSelector } from '@hyperfrontend/ui-utils/selector'

const selector = new CssSelector('div').class('card').attribute('data-status', 'active').hover().toString() // 'div.card[data-status="active"]:hover'

// Color manipulation
import { getColorVariation, hexToRgb, rgbToHex } from '@hyperfrontend/ui-utils/color'

const dimmedBlue = getColorVariation('#0066cc', 128) // 'rgba(0,51,102,0.5019607843137255)'
const rgb = hexToRgb('#ff5500') // { r: 255, g: 85, b: 0 }
const hex = rgbToHex(255, 85, 0) // '#ff5500'

// Gesture detection with cleanup
import { createGestureListener } from '@hyperfrontend/ui-utils/event'

const cleanup = createGestureListener(() => console.log('Escape or pinch detected'))
// Later: cleanup() to remove listeners

API Overview

One rule organises the whole surface: anything that attaches something hands back the function that detaches it. addStylesheet returns a tuple of the <style> element it injected and the function that removes it; onElementResize and createGestureListener return that remover on its own, one call closing all four listeners in the gesture case. Teardown is a list of functions you are already holding rather than a hunt through the document, which is what the counters above are counting.

The second shape to know is what createElement hands back: not the node, but an object around it carrying attachTo, detachFromParent, addChild, removeChild, show, hide, a visible flag, and ref, the live element for anything the wrapper does not do. show and hide take an optional duration in milliseconds and transition opacity over it. The tag shorthands (div, button, canvas and twenty-one others) are the same function with the tag already chosen.

Targets are elements or selector strings, interchangeably, and that is what lets syncElementDimensions pin an overlay to a third-party node before that node exists: underneath, getElementAsync polls every 100ms, gives up after 10 seconds, and the cleanup it returns cancels the poll if you gave up first.

Ten secondary entry points sit beside the root one, and they exist for weight rather than filing: importing from @hyperfrontend/ui-utils/color costs the color conversions and nothing else, which is what lets any of this into an embed with a few kilobytes to spend. Two are worth naming because their names give nothing away: /time is a promise delay and a UTC timestamp formatter, and /misc is one function, simpleHash, which turns a string into six characters (simpleHash('hello world') returns 'to5x38').

Every export, option and type is in the API reference, listed under the entry point it belongs to.

Compatibility

Runs on

  • Node.js>=18.0.0partially supported
  • Browserssupported
  • Web Workerssupported

Some utilities require browser APIs; check individual exports.

Ships as

  • ESMTree-shakeable
  • CJSNode and older bundlers
  • IIFEHyperfrontendUIUtils
  • UMDHyperfrontendUIUtils

CDN Usage

<!-- unpkg -->
<script src="https://unpkg.com/@hyperfrontend/ui-utils"></script>

<!-- jsDelivr -->
<script src="https://cdn.jsdelivr.net/npm/@hyperfrontend/ui-utils"></script>

<script>
  const { createElement, hexToRgb, rgbToHex } = HyperfrontendUIUtils
</script>

Global variable: HyperfrontendUIUtils

Architecture Highlights§

Each capability sits behind its own secondary entry point (/element, /style, /selector, /color, /event, /audio, /mobile, /time, /misc, /component), so importing one never drags in the rest. Everything is built on plain browser APIs (ResizeObserver, touch events, Web Audio) with no third-party dependencies.

API Reference§

View:
Organized by entry point

Module Structure

|

11 modules · 154 total exports

@hyperfrontend/ui-utils

UI utilities for audio, color, components, elements, events, selectors, and styling.

61 fn1 cls3 int12 type

@hyperfrontend/ui-utils/audio

Audio context initialization utilities.

1 fn

@hyperfrontend/ui-utils/color

Color manipulation utilities for RGB/hex conversions and color variations.

5 fn1 int

@hyperfrontend/ui-utils/component

Styled DOM component factory with style and create functions.

1 fn2 type

@hyperfrontend/ui-utils/element

DOM element creation, retrieval, and dimension synchronization utilities.

28 fn1 int7 type

@hyperfrontend/ui-utils/event

Synthetic mouse events and gesture listener utilities.

2 fn2 type

@hyperfrontend/ui-utils/misc

Miscellaneous UI utilities including simple string hashing.

1 fn

@hyperfrontend/ui-utils/mobile

Mobile device detection utilities.

1 fn

@hyperfrontend/ui-utils/selector

CSS selector builder and validation utilities.

13 fn1 cls

@hyperfrontend/ui-utils/style

Dynamic styling utilities for CSS rules and stylesheet management.

7 fn1 int1 type

@hyperfrontend/ui-utils/time

Animation-frame based pause and timestamp formatting utilities.

2 fn

Browse guides filtered to this packageSuggest a guide