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)