Import the javascript file with import { Xt } from 'xtendui'.


Activate usability logs with import 'xtendui/src/usability'. Xtend UI will sends warning messages with website usability suggestions.

SyntaxDefault / ArgumentsDescription
VariableXt.usabilityHostnames:Boolean|String' localhost'Enable usability checks on hostnames separated by space
VariableXt.usabilityIgnore:String'.sf-toolbar, .gm-style'Disable usability checks inside this query


You can execute a function on Document.readyState, by default it listens when document is ready.

SyntaxDefault / ArgumentsDescription
VariableXt.ready:Function{ func:Function, state:String = 'interactive complete', raf:Boolean = false }Execute a function on Document.readyState, states separated by space, can be 'loading''interactive''complete'


You can add Javascript code as a vanilla component with Xt.mount.

Mount listens and execute the query with Mutation Obsever. So the code gets executed also if the Node is added on the DOM asynchronously.

You can return a function to execute when the Node is removed from the DOM.

You can also use the class .xt-ignore when moving objects to prevent mount and unmount.

Xt.mount doesn't unmount/remount nodes not removed from html (e.g. when moving nodes inside DOM).

SyntaxDefault / ArgumentsDescription
Optionmatches:QuerynullQuery to match for mount
Optionroot:NodenullOnly if added nodes are inside a root node
Optionraf:BooleanfalseUse requestAnimationFrame for mount as with Xt.ready
OptionignoreMount:Query|false'.xt-ignore'Ignore mount on nodes with closest this query.
OptionignoreUnmount:Query|false'.xt-ignore'Ignore unmount on nodes with closest this query.
Optionmount:FunctionnullFunction to execute on mount, returned function will be executed on unmount

Here's mount function arguments.

Variableref:NodeMounted node
Variableobj:ObjectMounted object
Variableindex:NumberMounted index on the same mount
  matches: '.my-query',
  mount: ({ ref, obj, index }) => {
    // logic

    console.debug('mounted', ref, obj, index)

    // unmount

    return () => {
      console.debug('unmounted', ref)

Xt.on and

To show/hide and animate nodes we use custom Tailwind CSS variants that react to classes.

Use off:hidden out:pointer-events-none to hide with display: none; the node when not activated or animating.

Alternatively you can use your own custom style, for example off:invisible off:pointer-events-none out:pointer-events-none.

Use absolute top-0 left-0 right-0 on:relative to position the node in absolute mode when not activated.

You can toggle activations with javascript.

MethodXt.on({ el:Node, ns:String = '', duration:Number|null = null, raf:Boolean = true, initial:Boolean = false, callback:Function|null })Activate node with, set initial for instant animations{ el:Node, ns:String = '', duration:Number|null = null, raf:Boolean = true, initial:Boolean = false, callback:Function|null })Dectivate node with, set initial for instant animations

You can also assign duration on single nodes with data-xt-duration="Milliseconds" or data-xt-duration-in="Milliseconds" and data-xt-duration-out="Milliseconds"

Use Tailwind CSS variants off:, group-off:, on:, group-on:, in:, group-in:, out:, group-out: to assign animations.

You can use also css animations, just add them with class names .on, .in, .out, .done, .dir-before and .dir-after.


You can get self object from DOM node on Xtend UI components.

MethodXt.get({ name:String, el:Node })Get self object on DOM node for that component name (e.g. 'xt-toggle')

For example if you want to get the drop object on a particular node.

let self = Xt.get({ name: 'xt-drop', el: document.querySelector('.my-container') })

The components initialization of data-xt- or Xt.mount is ready after document ready, so if you use react use useLayoutEffect hook or Xt.ready or Xt.mount or init.xt. event to access the data after document ready.


You can set default options for all components of the same type, they get applied after default options and before custom options.

VariableXt.options:ObjectSet default options for that component name (e.g. 'xt-toggle')

For example if you want all drops to have a duration of 500.

Xt.options['xt-drop'] = {
  duration: 500,

Be sure to assing Xt.options in a imported setup file before all other components imports or the data-xt- initialized components doesn't have those options.


You can sanitize a html string with DOMPurify using Xt.sanitize. This method is used also internally to sanitize content added to DOM.

MethodXt.sanitize(str:String)Sanitize string with DOMPurify, returns String


You can create DOM node from string with this method. The string is automatically sanitized with Xt.sanitize.

MethodXt.node({ str:String, sanitize:Boolean = true })Create DOM node from string, returns Node
MethodXt.nodes({ str:String, sanitize:Boolean = true })Create DOM nodes from string, returns NodeList


You can check if node is visible with display with this method.

MethodXt.visible({ el:Node })Check if node is visible with display, returns Boolean


You can add external scripts to document with this method that gets executed immediately.

MethodXt.script({ url:String, callback:Function = null, defer:Boolean = true, async:Boolean = true })Add script to body


You can query multiple nodes at once with this method.

Method`Xt.queryAll({ els:NodeListArray, query:String })`


You can get translate values with this method.

MethodXt.getTranslate({ el:Node })Get [x, y] translate values on a DOM node, returns Array


You have some utilities for viewport height that changes only on horizontal resize, useful to have mobile viewport height that doesn't resize on vertical scroll.

VariableXt.innerHeight:NumberGet window height without mobile resize on page scroll

Or also use css variables for viewport height --vh.

.my-selector {
  height: 100vh;
  height: calc(var(--vh, 1vh) * 100);


For resize event we use a special event resize.xt that gets triggered only once after a delay. Also fixes interaction jumping on mobile devices because it doesn't trigger on vertical scroll/resize on mobile when viewport width doesn't change and matchMedia('(hover: none)').matches.

To force the resize.xt event you can dispatch resize event with detail.force = true.

dispatchEvent(new CustomEvent('resize', { detail: { force: true } }))

You can customize the delay of resize and medialoaded events.

SyntaxDefault / ArgumentsDescription
VariableXt.resizeSkip:Function() => matchMedia('(hover: none), (pointer: coarse)').matchesSkip trigger resize.xt on vertical only resize if this condition is met
VariableXt.resizeDelay:Number|false200Delay for the resize.xt event
VariableXt.medialoadedDelay:Number|falsefalseDelay for the mediaLoaded event


If you need to access Xt variable in the global window use window.XtSetGlobal in a script tag before the main application or in your testing environment.

SyntaxDefault / ArgumentsDescription
Variablewindow.XtSetGlobal:Boolean|StringnullEnable window.Xt global variable


Listen to events on a single Node.

const node = document.querySelector('.my-node')

const on = e => {
  // logic

node.addEventListener('eventname.xt.componentname', on)

Listen to events on multiple Nodes.

for (const node of document.querySelectorAll('.my-node')) {
  const on = e => {
    // logic

  node.addEventListener('eventname.xt.componentname', on)

Listen to events on multiple Nodes with events delegation useCapture.

This method is useful to capture events also if child nodes gets added in future.

const container = document.querySelector('.my-container')

let self = Xt.get({ name: 'xt-componentname', el: container })

const on = e => {
  const tr =
  // useCapture event propagation check
  if (self.targets.includes(tr)) {
    // logic

container.addEventListener('eventname.xt.componentname', on, true) // useCapture event propagation