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 slot Kebab 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 tree Attribute change hooks By 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.