A modular DOM helper library.
npm install domestique
Note: This library is written as ES2015 code and published as such to npm. Read the Compatibility section for more information.
import {
// Dimension
inViewport,
scrollbarSize,
viewportHeight,
viewportWidth,
// Element
activeElement,
create,
addClass,
removeClass,
hasClass,
data,
focus,
isFocusable,
isTabbable,
parents,
render,
// Event
delegate,
dispatch,
on,
onTransitionEnd,
off,
ready,
// Query
closest,
find,
focusable,
matches,
select,
selectAll,
tabbable
} from 'domestique';
inViewport(element: Element): bool
Returns true
if any part of an element is in the viewport.
const inVp = inViewport(element);
scrollbarSize(): number
Returns the size of the scrollbar in pixels.
const size = scrollbarSize();
viewportHeight(): number
Returns the viewport height.
Note: The height represent the CSS viewport height (@media (height)) including the size of a rendered scroll bar (if any).
const vpHeight = viewportHeight();
viewportWidth(): number
Returns the viewport width.
Note: The width represent the CSS viewport width (@media (width)) including the size of a rendered scroll bar (if any).
const vpWidth = viewportWidth();
activeElement(): Element
Returns the element that currently has focus.
const element = activeElement();
create(html: string): Element
Creates a DOM element from a HTML string. If it's already a DOM node, the node is returned as is.
const element = create('<div/>');
addClass(element: Element, className: string): void
Adds a class (or multiple classes separated by space) to an element.
addClass(element, 'my-class');
addClass(element, 'my-class my-other-class');
removeClass(element: Element, className: string): void
Removes a class (or multiple classes separated by space) from an element.
removeClass(element, 'my-class');
removeClass(element, 'my-class my-other-class');
hasClass(element: Element, className: string): bool
Checks whether an element has a class (or multiple classes separated by space).
const hasClass = hasClass(element, 'my-class');
const hasAllClasses = hasClass(element, 'my-class my-other-class');
data(element: Element, name: string): bool
Reads and parses data from an data-* attribute.
<div
data-string="string"
data-true="true"
data-false="false"
data-null="null"
data-integer="1"
data-float="1.2"
data-json-object="{"foo": "bar"}"
data-json-array="["foo"]"
></div>
const stringValue = data(element, 'string');
const trueValue = data(element, 'true');
const falseValue = data(element, 'false');
const nullValue = data(element, 'null');
const integerValue = data(element, 'integer');
const floatValue = data(element, 'float');
const jsonObjectValue = data(element, 'json-object');
const jsonArrayValue = data(element, 'json-array');
focus(element: Element[, options: object]): void
Shifts focus to an element.
focus(element);
Browsers scroll the focused element into view. focus()
provides an option
restoreScrollPosition
to restore scroll positions of all scroll containers of
the focused element to the state before the element got focus.
focus(element, {
restoreScrollPosition: true
});
isFocusable(element: Element): bool
Checks whether an element is focusable.
Unlike isTabbable()
, the function also returns true
for
elements which are not focusable by the keyboard, but only by script
(element.focus()
) and possibly the mouse (or pointer). Usually, those are
elements with a negative tabindex
attribute value, like -1
.
const isFocusableElement = isFocusable(element);
isTabbable(element: Element): bool
Checks whether an element is tabbable.
Unlike isFocusable()
, the function returns true
only for
elements which are focusable by the keyboard (by pressing the TAB and
SHIFT+TAB keys). Elements that are only focusable by
script (element.focus()
) and possibly the mouse (or pointer) are excluded.
const isFocusableElement = isFocusable(element);
parents(element: Element): Array
Returns an array of the element's parent elements.
const parentElements = parents(element);
render(html: string): object
Creates and returns DOM element references from a HTML string.
Elements must have a ref
attribute with the reference name. The value of this
attribute will get mapped to the property name of the returned object.
const {list, 'list-items': listItems} = render(`
<ul ref="list">
<li ref="list-items[]"></l>
<li ref="list-items[]"></l>
</ul>
`);
Note: The
ref
attributes will be removed from the returned elements.
delegate(target: EventTarget, type: string, selector: string, listener: EventListener[, options: object]): function
Registers a listener
for the event type
on target
with options
that
processes events from descendant elements of target
matching the specified
selector
.
The function returns another function which can be used to unregister the event listener.
const listener = function (e, target) {
target.classList.add('my-target-clicked');
console.log('My Button clicked');
};
const options = {
passive: true
};
const remove = delegate(
document, // Listen on document
'click',
'.my-button',
listener,
options
);
remove(); // Remove event listener
dispatch(target: EventTarget, type: string[, eventInit: CustomEventInit]): bool
Dispatches a CustomEvent
type
at the specified target
optionally using the eventInit
options.
The function returns false
if the event is cancelable and at least one of the
event handlers which handled this event called Event.preventDefault()
.
Otherwise it returns true
.
const clickNotCancelled = dispatch(document, 'click');
const myEventNotCancelled = dispatch(
document.querySelector('.my-button'),
'my:event',
{
bubbles: true,
cancelable: true,
detail: {
foo: 'bar'
}
}
);
on(target: EventTarget, type: string, listener: EventListener[, options: object]): function
Registers a listener
for the event type
on target
with options
.
options
is always an object that specifies characteristics about the event
listener, see https://developer.mozilla.org/docs/Web/API/EventTarget/addEventListener.
If one of the options isn't supported by the browser, the behavior is as follows:
capture
: Always supported.once
: Will be polyfilled.passive
: Will be ignored.
The function returns another function which can be used to unregister the event listener.
const target = document.querySelector('.my-button');
const listener = function () {
console.log('My Button clicked');
};
const options = {
once: true
};
const remove = on(
target,
'click',
listener,
options
);
remove(); // Remove event listener
onTransitionEnd(target: EventTarget, listener: EventListener): function
Registers a one-time listener
for the transitionend
event on target
.
The function returns another function which can be used to unregister the event listener.
const target = document.querySelector('.my-element');
const listener = function (target) {
target.classList.add('transition-ended');
console.log('Transition ended');
};
const remove = onTransitionEnd(
target,
listener
);
remove(); // Remove event listener
off(target: EventTarget, type: string, listener: EventListener[, options: object]): void
Removes a listener previously registered via on()
.
off(
target,
'click',
listener,
options
);
ready(listener: function): void
Registers a listener to be called once the DOM is ready.
Unlike DOMContentLoaded
, this also works when called after the DOM was loaded.
ready(function () {
console.log('DOM is ready!');
});
closest(element: Element, selector: string): Element
Returns the closest ancestor of the element
(or the element
itself) which
matches the specified selector
.
If there isn't such an ancestor, it returns null
.
const closestParagraph = closest(element, 'p');
Deprecated in favor of selectAll(). To be removed in 2.0.
find(selector: string[, element: Element]): array
Returns an array
of elements matching the specified selector
which are
descendants of the document
or the element
specified as optional second
argument.
const paragraphs = find('p');
const spansInsideFirstParagraph = find('span', paragraphs[0]);
focusable([element: Element]): array
Returns an array
of focusable elements in the DOM which are
descendants of the document
or the element
specified as optional first
argument.
Unlike tabbable()
, the array also includes elements which are not
focusable by the keyboard, but only by script (element.focus()
) and possibly
the mouse (or pointer). Usually, those are elements with a negative tabindex
attribute value, like -1
.
Note: The elements in the array are ordered according to the sequential focus navigation order which may be different from the DOM order.
const focusableElements = focusable();
matches(element: Element, selector: string): boolean
Returns true
if the element
would be selected by the specified selector
,
false
otherwise.
const isParagraph = matches(element, 'p');
select(context: Element, selector: string): Element
Returns the descendant of context
(document
or Element
) which matches the
specified selector
. If no element could be found, null
is returned.
const paragraph = select(document, 'p');
const spanInsideParagraph = select(paragraph, 'span');
select(context: Element, selector: string): array
Returns an array
of all descendants of context
(document
or Element
)
which match the specified selector
.
const allParagraphs = selectAll(document, 'p');
const allSpansInsideFirstParagraph = selectAll(paragraph[0], 'span');
tabbable([element: Element]): array
Returns an array
of keyboard focusable ("tabbable") elements in the DOM which
are descendants of the document
or the element
specified as optional first
argument.
Unlike focusable()
, the array only includes elements which
are focusable by the keyboard (by pressing the TAB and
SHIFT+TAB keys). Elements that are only focusable by
script (element.focus()
) and possibly the mouse (or pointer) are excluded.
Note: The elements in the array are ordered according to the sequential focus navigation order which may be different from the DOM order.
const tabbableElements = tabbable();
This library is written as ES2015 code and published as such to
npm.
It is compatible with
modern browsers
which natively support <script type="module">
.
If support for older browsers is required, code from domestique
must be
transpiled, eg. by using Babel.
Most bundlers (like Webpack and
Rollup) recommend
to not transpile anything from the node_modules/
directory. It must be
ensured, that code from domestique
is not excluded from transpilation.
If you're using Webpack and Babel, that could look like:
{
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules\/(?!domestique)/,
loader: 'babel-loader'
}
]
}
}
After transpilation, domestique
supports the
most common browsers including IE 10
without polyfills.
- BrowserStack for providing free VMs for automated testing.
- GitHub for providing free Git repository hosting.
- npm for providing the package manager for JavaScript.
- TravisCI for providing a free build server.
Copyright (c) 2018-2021 Jan Sorgalla. Released under the MIT license.