Introduction What is Modjool? Modjool is a lightweight JavaScript framework for creating user interface components. It's ideal for creating UI libraries and simple reusable components. It does this by allowing for easy creation of native custom elements (with custom attributes), for example: <info-box title="Important message" info>The action has been completed</info-box> The action has been completed Change attribute, info -> success In the example above, replacing the info attribute with success updates the style & HTML of the component. Press the Play button button above to try it for yourself. Web components The primary aim of Modjool is to create UI elements, however Modjool allows for the creation of dynamic web components too: <local-clock timezone="0">Loading..</local-clock> Loading.. Change attribute, timezone="+3" Outline of features Modjool makes use of the web components suite, but abstracts away the boilerplate, leaving you with an uncomplicated, easy-to-read API. Plus, it works natively in the browser; no compilation step is necessary. Simplicity - simplify away classes, styling, multiple HTML tags, into one custom element --- HTML templates - use attributes, slots, dynamic content & more --- CSS templates - with scoped CSS, and all the above --- Lifecycle events - run JS at different points in an element's lifecycle --- Reactive data - body updates when the data changes --- Pairs up - works wonderfully with CSS libraries, such as Tailwind, Bulma, Bootstrap Modjool also fully supports the shadow DOM (an optional feature), but takes cares of all the complicated work in the background, so you can use the same API for elements regardless of whether it's enabled or not. Getting started The simplest way to try Modjool is with our CodeSandbox project. Alternatively, create an HTML file, and include Modjool with: <script src="https://unpkg.com/modjool"></script> The Installation page features more install options. Basic elements Creating a custom element is simply one line of code with the Basic API, read more here, though for now, we'll skip to the interesting stuff. Creating advanced elements More complex elements can be built using the Advanced API. The advanced API allows you to easily make use of slots, attribute values, lifecycle events, scoped css, and more. Modifying the body The advanced API uses a number of hooks to define the element's HTML & CSS, but also to run code at various points in the element's lifecycle. The html hook allows you to define the content of the element's body: modjool.create({ tag: 'fruit-element', html: ({ slot }) => ` <b>${slot}</b> is a fruit. ` }) <fruit-element>Apricot</fruit-element> Apricot Here we've used html in conjunction with the destructured slot parameter. Slots are used to return the innerHtml of the element (or the outerHtml if multiple are used, more info). A number of parameters are available to access various properties and functions from within hooks. Variables in CSS Custom CSS can be defined and set within Modjool elements using the css hook: modjool.create({ tag: 'fruit-element', html: ({ attr, slot }) => ` <b>${slot}</b> is a fruit. It's ${attr.color || 'black'}. `, css: ({ attr }) => ` b { color: ${attr.color || 'black'}; } ` }) <fruit-element color="red">Cherry</fruit-element> Cherry In this example we take the color attribute value, from the HTML element, using the attr parameter, and pass it the HTML and CSS. By default, all CSS is scoped, and will only affect the current instance of the current element. You may have noticed ${attr.color || 'black'} above. Using the logical OR operator like this is an easy way to define default values, in case the attribute doesn't exist: <fruit-element>Blackberry</fruit-element> Blackberry Using data The data parameter allows you to pass data to and from different parts of the element, and generally makes it easier to create simpler templates. In this snippet, the js hook is used, a lifecycle event that fires when the element is created, and the text property of data is set (if the element has a slot). js: ({ attr, data, slot }) => { if (slot) { data.text = `<b>${slot}</b> is a fruit. It's ${attr.color || 'black'}.` } }, html: ({ data }) => ` <div>${data.text || 'No fruit here'}</div> ` If the element has no innerHtml then slot will return a falsy value. Here we've used this to check if we should set data.text or not. data comes with its own hook, to define the object before the element is written to the DOM, helping to provide separation of concerns. You can also use this to set default values for different properties: data: ({ attr }) => ({ subtitle: attr.subtitle || 'Default title:', text: 'No fruit here' }) data is reactive, and will update the body every time it's properties are modified, if the body has changed. Note that the data hook is a function that returns an object (using parentheses around curly braces returns an object in arrow functions). A complex element If we put everything we've just learnt together, then we can define a set of default data properties, modify the main text if there is a slot, and then output the HTML and CSS using those properties: modjool.create({ tag: 'fruit-element', data: ({ attr, slot }) => ({ color: attr.color || 'black', subtitle: attr.subtitle || 'Default title', text: 'No fruit here.' }), js: ({ data, slot }) => { if (slot) { data.text = `<b>${slot}</b> is a fruit. It's ${data.color}.` } }, html: ({ data }) => ` <strong>${data.subtitle}</strong> <div>${data.text}</div> `, css: ({ data }) => ` b { color: ${data.color}; } ` }) <fruit-element subtitle="Fruit info" color="green">Pear</fruit-element> Pear <fruit-element></fruit-element> The completed fruit-element is available to play with over on CodeSandbox. Ready for more? Congratulations! You've now learnt the basics of Modjool's Advanced API! The rest of the guide will go into Modjool with finer detail, giving you examples along the way.