Attributes
Modjool provides easy access to the custom element's attributes,
allowing for simple use within templates and lifecycle events.
Getting Attributes
Attributes can be retrieved using the attr instance parameter:
modjool.create({
tag: 'attr-example',
html: ({ attr }) => `
<b>${attr.title}</b>
<div>${slot}</div>
`
})<attr-example title="This is the title">Here's a slot</attr-example>Here's a slotKebab case conversion
Any attributes written in kebab-case will automatically be
converted to camelCase, which enables easier access to properties, for example:
// custom-attribute="Hello"
// ❌ Invalid JavaScript
attr.custom-attribute
// ❌ Incorrect
attr['custom-attribute']
// ✅ Correct
attr.customAttribute
Automatic kebab/camel conversion in use within a lifecycle hook:<!-- 'text-label' -->
<custom-element text-label="Important label"></custom-element>// 'text-label' converted to 'textLabel'
js: ({ attr ]) => {
// 'Important label'
console.log(attr.textLabel)
// <custom-element text-label="A new label">
attr.textLabel = 'A new label'
}Two-way binding
Attributes have a two-way binding by default,
meaning that when a property
belonging to attr is updated, the actual
attribute attached to the HTML element is also updated.
modjool.create({
tag: 'reactive-attr',
js: ({ attr, slot }) => {
// If more than 10 characters in (single) slot
// then add size="wide"
if (slot.length > 10) {
attr.size = 'wide'
}
},
css: () => `
:self {
display: inline-block;
background: aliceblue;
}
/* Wide element has different styling */
:self([size="wide"]) {
display: block;
background: mistyrose;
}
`
})
In this example, we give <reactive-attr> the size="wide" attribute,
which is styled differently in the css hook, if the element's
slot has more than 10 characters:
<reactive-attr>Oak</reactive-attr>Oak<reactive-attr>Silver birch or cherry tree</reactive-attr>Silver birch or cherry treeAttribute change hooksBy default, when an attribute is changed or
defined on the element, if a correspondingly
named hook exists (after conversion to camelCase), it will be invoked:
<!-- 1. Heading attribute is defined, attr_heading hook called -->
<custom-element heading="This is a heading"></custom-element>js: ({ attr }) => {
// 2. Heading attribute changed, attr_heading hook called again
attr.heading = 'Hello'
},
// attr_heading hook
attr_heading: ({ attr, slot }) => {
...
}
We refer to this as the attr_[name] hook in the API. This custom hook is passed
two extra instance parameters, oldVal and newVal, which are
respectively the previous and the new attribute values for the changed attribute.
In this example, we make use of oldVal to output the previous value. We also
set a simple click event on the element, that increments the counter attribute:
modjool.create({
tag: 'attribute-hook',
js: ({ attr, elem }) =>
// Click event: add one to counter
elem.onclick = () => attr.counter++
},
attr_counter: ({ data, oldVal }) => {
// Set 'before' to previous value of 'counter'
data.before = oldVal
},
html: ({ attr, data }) => `
Before: ${data.before || 'N/A'}
Count: ${attr.counter}
`
})
<attribute-hook counter="1"></attribute-hook>In the background
Attribute change hooks are called immediately after an attribute is changed, through any means,
and are followed by a call to the complete hook, this hook being especially
handy for rebuilding event listeners after the body has refreshed, read more.
Simple, right?
On the next page, we'll be learning about running JavaScript at different times in the element's lifecycle.