id-dom
v0.0.4
Published
Deterministic DOM element getters by ID (typed, tiny, modern).
Maintainers
Readme
id-dom
Deterministic DOM element getters by ID — typed, tiny, modern.
id-dom is a small utility for grabbing DOM references safely by id, with predictable behavior:
- Typed getters like
button('saveBtn'),input('nameInput'),svg('icon') - Strict or optional mode (
throwvsnull) - Short optional alias via
.opt - Scoped lookups for
document,ShadowRoot,DocumentFragment, or anElement - Centralized error handling with
onErrorand optionalwarn - Zero deps
This is deliberately not a selector framework. It is a tiny, ID-first primitive for safe DOM wiring.
Install
npm install id-domQuick Start
import dom from 'id-dom'
const saveBtn = dom.button('saveBtn')
saveBtn.addEventListener('click', save)Optional access never throws for missing or wrong-type elements:
const debug = dom.div.optional('debugPanel')
debug?.append('hello')
const maybeCanvas = dom.canvas.opt('game')Why ID-first?
Using getElementById is:
- fast
- unambiguous
- easy to reason about
And with typed getters, you immediately know whether you got a HTMLButtonElement, HTMLInputElement, SVGSVGElement, and so on.
When scoped roots do not support getElementById, id-dom falls back to querySelector(#id) and safely escapes edge-case IDs.
API
Default export: dom
The default export is a scoped instance using document (when available) with strict behavior:
- missing element → throws
- wrong type or wrong tag → throws
- invalid input → throws
import dom from 'id-dom'
const name = dom.input('nameInput')
const submit = dom.button('submitBtn')createDom(root, config?)
Create a scoped instance that searches within a specific root:
document→ usesgetElementByIdShadowRoot,DocumentFragment, orElement→ usesquerySelector(#id)fallback
import { createDom } from 'id-dom'
const d = createDom(document, { mode: 'null', warn: true })
const sidebar = d.div('sidebar')Config
type DomMode = 'throw' | 'null'
{
mode?: DomMode
warn?: boolean
onError?: (err: Error, ctx: any) => void
}byId(id, Type, config?)
Generic typed lookup:
import { byId } from 'id-dom'
const btn = byId('saveBtn', HTMLButtonElement)Optional variants:
const maybeBtn = byId.optional('saveBtn', HTMLButtonElement)
const maybeBtn2 = byId.opt('saveBtn', HTMLButtonElement)Behavior
- valid match → returns the element
- missing element → throws or returns
null - wrong type → throws or returns
null - invalid
id→ throws or returnsnull - invalid
Type→ throws or returnsnull
tag(id, tagName, config?)
Tag-based validation when constructor checks are not the right fit:
import { tag } from 'id-dom'
const main = tag('appMain', 'main')
const icon = tag('icon', 'svg', { root: container })Optional variants:
const maybeMain = tag.optional('appMain', 'main')
const maybeMain2 = tag.opt('appMain', 'main')Behavior
- valid tag match → returns the element
- missing element → throws or returns
null - wrong tag → throws or returns
null - invalid
id→ throws or returnsnull - invalid
tagName→ throws or returnsnull
Built-in Getters
Typed getters
Available on dom and on any createDom() instance:
el(id)→HTMLElementinput(id)→HTMLInputElementbutton(id)→HTMLButtonElementtextarea(id)→HTMLTextAreaElementselect(id)→HTMLSelectElementform(id)→HTMLFormElementdiv(id)→HTMLDivElementspan(id)→HTMLSpanElementlabel(id)→HTMLLabelElementcanvas(id)→HTMLCanvasElementtemplate(id)→HTMLTemplateElementsvg(id)→SVGSVGElementbody(id)→HTMLBodyElement
Each getter also has:
dom.canvas.optional('game')
dom.canvas.opt('game')Common tag helpers
main(id)→ validates<main>section(id)→ validates<section>small(id)→ validates<small>
Each also supports .optional and .opt.
Error Handling
Throwing mode
import dom from 'id-dom'
dom.button('missing') // throwsNull-returning mode
import { createDom } from 'id-dom'
const d = createDom(document, { mode: 'null' })
d.button('missing') // nullCentral reporting
const d = createDom(document, {
mode: 'null',
onError: (err, ctx) => {
// sendToSentry({ err, ctx })
},
})Enable console warnings too:
createDom(document, { mode: 'null', warn: true })Scoped Roots
Shadow DOM
import { createDom } from 'id-dom'
const host = document.querySelector('#widget')
const shadow = host.attachShadow({ mode: 'open' })
shadow.innerHTML = `<button id="shadowBtn">Click</button>`
const d = createDom(shadow)
const btn = d.button('shadowBtn')Element root
const container = document.querySelector('#settings-panel')
const d = createDom(container)
const input = d.input('emailInput')SVG in scoped roots
const container = document.querySelector('#icons')
const d = createDom(container)
const icon = d.svg('logoMark')Notes
el(id)is specifically forHTMLElement, not every possible DOMElement.body(id)looks up a<body>by ID. This library stays ID-first on purpose.tag()can validate non-HTML tags too, such assvg, when used against supported scoped roots.
Browser Support
Modern browsers supporting:
getElementByIdquerySelector
CSS.escape is used when available. A safe internal fallback is included for environments such as some jsdom builds where it may be missing.
License
See LICENSE.
