DOM References

There could be times when you need to get reference of the element in the DOM to perform something specific to your project. Fortunately, Markup makes it easy get reference of DOM elements.

Markup exposes a special attribute you can use to create DOM references. It is the ref attribute.

const button = html`<button ref="btn">click me</button>`

button.render(document.body)

button.refs.btn[0].style.setProperty('color', 'red')

The example above sets a ref attribute with the value of btn which is the name for your reference.

To access the reference it reads the refs property on the HTMLTemplate that is an object literal keyed by the name of references you created.

Each ref will be an array of elements, that is why it is accessing the first item in that array to set the color to red.

Grouped references

By default, all references are grouped because every reference returns an array of elements.

What this means is that you can use the same ref value for multiple elements and this will include all of them.

const todos = [
  'Go to gym',
  'Buy groceries',
  'Pick up the kids'
].map(todo => html`<div class="todo-item" ref="todo">${todo}</div>`)

const todoList = html`${todos}`;

todoList.render(document.body)

todoList.refs.todo // contains 3 DIVs

The above example simple how this ability is a quick way to collect a list of DOM elements to do whatever you want.

Nested references

You can nest multiple templates containing ref attribute, you may collect these references via the individual template itself or in the parent most template.

const button = html`<button ref="btn">+</button>`;

let count = 0;

const countUp = html`<span>${count}</span> ${button}`;

countUp.render(document.body);

button.refs.btn // [HTMLButtonElement]
countUp.refs.btn // [HTMLButtonElement]

Feel free to collect those reference from whichever template you like but this feature will make it convenient to consume your references in one place instead.

Dynamic references

You can only collect references from templates that have been rendered at least once. That is why Markup references are created as needed with every change.

If you have templates that are dynamically rendered, you can collect these references as the DOM changes.

let loading = true;

const sample = html`${
  () => loading 
    ? html`<p ref="loading">loading</p>` 
    : html`<p ref="loaded">loaded</p>`}`

sample.render(document.body);

// refs object will not contain the "loaded" ref
// because it was never rendered
sample.refs // {loading: [P]}

sample.onUpdate(() => {
  sample.refs // {loading: [P], loaded: [P]}
})

setTimeout(() => {
  loading = false;
  sample.update(); // trigger update
}, 2500)