@polight/lego
Version:
Tiny Web Components lib for future-proof HTML mentors
367 lines (314 loc) • 47.3 kB
JSON
{"0": {
"doc": "Build Native Web-Components",
"title": "Quick start",
"content": "Installation . If you don’t have a package.json file yet, initialize first with npm init (or yarn init). Install the compiler with npm i @polight/lego (or yarn add @polight/lego). Basic Example . This is the file tree we will need for this example: . index.html |- bricks/ |- hello-world.html → The HTML you typed . Hello World . Create a file called bricks/hello-world.html: . <script> const state = { name: \"World!\" } } </script> <template> <p>Hello ${ state.name }</p> </template> . Compile with npx lego (or yarn lego) . And use you component in your /index.html: . <script src=\"./dist/index.js\" type=\"module\"></script> <hello-world></hello-world> . Run a local web server, eg: npx sirv-cli and open http://localhost:5000. ",
"url": "/v1/getting-started/#quick-start",
"relUrl": "/v1/getting-started/#quick-start"
},"1": {
"doc": "Build Native Web-Components",
"title": "Let’s get a step back",
"content": "What did just happen? . Here’s what you just did with this simple code: . | you created a native HTML element called hello-world by creating bricks/hello-world.html | you made it react with a name state property | you imported all components from ./dist/index.js (well, only 1 for now) | you used the HTML element <hello-world></hello-world> | . No magic 🪄 here, just a couple of default configuration that you can override. You website is ready to be published on any static host, even Github Pages. ",
"url": "/v1/getting-started/#lets-get-a-step-back",
"relUrl": "/v1/getting-started/#lets-get-a-step-back"
},"2": {
"doc": "Build Native Web-Components",
"title": "Build Native Web-Components",
"content": "Lego requires npm or yarn and node. By default Lego compiles HTML components from the HTML files within the /bricks folder. Create the folder to host your future components: mkdir bricks. ",
"url": "/v1/getting-started/",
"relUrl": "/v1/getting-started/"
},"3": {
"doc": "Using Native Web-Components",
"title": "Usage of Lego web-components",
"content": "A web-component can optionally have 3 parts: some HTML in a <template> tag, some JavaScript in a <script> tag and some CSS in a <style> tag. You can make a web-component for muliple reasons. If you just want to re-use a piece of HTML, the <template> tag is all you need. If you want to polish it’s look 💅, <style> is your friend. Bonus: it’s fully scoped with no leaking out of context. When some user interaction or reactiveness is demanded, <script> is going to be the guy. ",
"url": "/v1/usage-web-components/#usage-of-lego-web-components",
"relUrl": "/v1/usage-web-components/#usage-of-lego-web-components"
},"4": {
"doc": "Using Native Web-Components",
"title": "Using Native Web-Components",
"content": ". | Usage of Lego web-components | . ",
"url": "/v1/usage-web-components/",
"relUrl": "/v1/usage-web-components/"
},"5": {
"doc": "Template Tag to write HTML in Web-Components",
"title": "Template Tag to write HTML in Web-Components",
"content": "<template> tag . An HTML content is written within a <template> tag. It’s just basic HTML augmented with a little of superpowers 🦸. Let’s call these superpowers “directives”. You may easily detect them as they are prefixed with : or @. Only 4 directives to know: . | :if to display a tag based on a condition | :for to repeat a tag | : to evaluate a string | @ to bind an event | . Note that :if and :for attributes, when used in the same tag should be used with an order in mind: <a :if=\"user\" :for=\"user in state.users\"> won’t work, but <a :if=\"state.users.length\" :for=\"user in state.users\"> will first evaluate if the users array has items, or <a :for=\"user in users\" :if=\"user\"> will check that each individual user has a value. <a :if=\"state.isAdmin\" :for=\"user in state.users\"> won’t loop at all if isAdmin is false. ",
"url": "/v1/usage-web-components/template/",
"relUrl": "/v1/usage-web-components/template/"
},"6": {
"doc": "Using Condition in Web-Components",
"title": "Using Condition in Web-Components",
"content": ":if Directive . Conditionally display a tag and its descendants. Example: <p :if=\"state.count < 5\">Less than 5</p> will be displayed if the condition is met. ",
"url": "/v1/usage-web-components/condition/",
"relUrl": "/v1/usage-web-components/condition/"
},"7": {
"doc": "Using loops in Web-Components",
"title": "Using loops in Web-Components",
"content": ":for Directive . Repeat a tag based on a property. The syntax is as follow: :for=\"item in state.items\". The item value will be available trough ${item} within the loop. If you need an incremental index i, use :for=\"item, i in state.items\". Example: <li :for=\"attendee in state.attendees\">${attendee}</li> with a state as this.state = { attendees: ['John', 'Mary'] } will display <li>John</li><li>Mary</li> . ",
"url": "/v1/usage-web-components/loop/",
"relUrl": "/v1/usage-web-components/loop/"
},"8": {
"doc": "Inserting Custom Attributes in Web-Components",
"title": "Inserting Custom Attributes in Web-Components",
"content": ": Custom Directive . A custom directive will interpret in JS whatever you pass as value. <script> function getUrl(id) { return `/user/${id}` } </script> <template> <a :href=\"getUrl('144')\">Visit Profile</a> </template> . outputs . <a href=\"/user/144\">Visit Profile</a> . Boolean attributes . Example: <input type=checkbox :checked=\"state.agreed\" :required=\"state.mustAgree\">. With the following state: const state = { agreed: false, mustAgree: true } would render <input type=checkbox required=\"required\">. ",
"url": "/v1/usage-web-components/custom-directive/",
"relUrl": "/v1/usage-web-components/custom-directive/"
},"9": {
"doc": "Bind an Event to a Web-Component",
"title": "Bind an Event to a Web-Component",
"content": "@ Directive for binding Events . <script> function sayHi(event) { const buttonName = event.target.name alert(`You clicked ${ buttonName } to says hi! 👋🏼`) } </script> <template> <button @click=\"sayHi\" name=\"the-button\">click</button> </template> . ",
"url": "/v1/usage-web-components/events/",
"relUrl": "/v1/usage-web-components/events/"
},"10": {
"doc": "Reactive Web-Components to Update HTML",
"title": "Reactive Web-Components to Update HTML",
"content": "Reactive Properties . The state is where the reactiveness takes place. declare a state object in the init() function with default values: . const state = { user: { firstname: 'John', lastname: 'Doe' }, status: \"Happy 😄\" } const title = \"This title is non-reactive\" . Displaying a state value is as simple as writing ${state.theValue} in your HTML. When you need your component to react, call the render() method with your updated state: . function updateStatus(event) { render({ status: \"Laughing 😂\" }) } . This will update your component only where needed. When state is just mutated, the changed(changedProps) is called. This changed() method is called before (re-)rendering. ",
"url": "/v1/usage-web-components/reactive/",
"relUrl": "/v1/usage-web-components/reactive/"
},"11": {
"doc": "Pass Attributes to Web-Components",
"title": "Pass Attributes to Web-Components",
"content": "Component Attributes . Attributes declared on the components will be all be accessible through the state. If the property is initialized in the this.state, the attribute will be reactive: . <x-user status=\"thinking 🤔\"><x-user> . status will therefore be reactive and the thinking 🤔 attribute value will overwrite the Happy 😄 default status. ⚠️ A property that is not declared in the state won’t be reactive. These properties can be accessed through this.getAttribute() from within the component. After all, these components are just native! 🏡 . Slots . Slots are part of the native web-component. Because Lego builds native web-components, you can use the standard slots as documented. Example: . index.html . <user-profile> <span>This user is in Paris</span> <user-profile> . bricks/user-profile.html . <template> <h1>User profile</h1> <p>important information: <slot></slot></p> </template> . Will write …<p>important information: <span>This user is in Paris</span></p> . See more advanced examples. Reactive CSS Within <style> . CSS is much more fun when it’s scoped. Here it come with the web-components. Here again, no trick, just the full power of web-components and scoping styles. Well, you should know that the css is reactive too! 😲 . Writing CSS is as easy as . <script> const state = { fontScale: 1 } </script> <template> <h1>Bonjour!</h1> </template> <style> :host { font-size: ${state.fontScale}rem; } h1 { padding: 1rem; text-align: center; } </style> . Host . :host is a native selector for web-components. It allows to select the current component itself. Variables . You can use variables in your CSS just like in your templates. Example: . <script> const state = { color: '#357' } </script> <template> <h1>Bonjour<h1> </template> <style> h1 { color: ${ state.color }; } </style> . will apply the #357 color onto h1. ",
"url": "/v1/usage-web-components/attributes/",
"relUrl": "/v1/usage-web-components/attributes/"
},"12": {
"doc": "Using slots to Insert Elements in Web-Components",
"title": "Using slots to Insert Elements in Web-Components",
"content": "Slots . Slots are part of the native web-component. Because Lego builds native web-components, you can use the standard slots as documented. Example: . index.html . <user-profile> <span>This user is in Paris</span> <user-profile> . bricks/user-profile.html . <template> <h1>User profile</h1> <p>important information: <slot></slot></p> </template> . Will write …<p>important information: <span>This user is in Paris</span></p> . See more advanced examples. ",
"url": "/v1/usage-web-components/slots/",
"relUrl": "/v1/usage-web-components/slots/"
},"13": {
"doc": "Using Reactive CSS to Update Styles in Web-Components",
"title": "Using Reactive CSS to Update Styles in Web-Components",
"content": "Reactive CSS <style> . CSS is much more fun when it’s scoped. Here it come with the web-components. Here again, no trick, just the full power of web-components and scoping styles. Well, you should know that the css is reactive too! 😲 . Writing CSS is as easy as . <template> <h1>Bonjour!</h1> </template> <script> export default class extends Lego { init() { this.state = { fontScale: 1 } } } </script> <style> :host { font-size: ${state.fontScale}rem; } h1 { padding: 1rem; text-align: center; } </style> . Host . :host is a native selector for web-components. It allows to select the current component itself. Variables . You can use variables in your CSS just like in your templates. Example: . <template> <h1>Bonjour<h1> </template> <script> export default class extends Lego { init() { this.state = { color: '#357' } } } </script> <style> h1 { color: ${ state.color }; } </style> . will apply the #357 color onto h1. ",
"url": "/v1/usage-web-components/reactive-css/",
"relUrl": "/v1/usage-web-components/reactive-css/"
},"14": {
"doc": "Insert JavaScript in a Web-Component",
"title": "<script extend> tag",
"content": "The “script extend” tag is has a special behavior. You will create a class extending the component, that’s how you extend your full component with advanced script. To do so extend the Lego class, that’s a naming convention: . export default class extends Lego { … } . From there you can catch connected() events, changed() when the state is updated, override setAttributes() and all other Lego or HTMLElement properties. It’s also a great place to define custom events or custom methods for your component that are accessible from the outside: . /bricks/my-element.html . <script extend> export default class extends Lego { getStatus() { return `you are requesting status of ${ this.nodeName }`) } connected() { console.info('the component is connected to the dom') } } </script> . /bricks/index.html . <my-element id=\"elem\"></my-element> <script> console.debug(document.querySelector('#elem').getStatus()) </script> . Accessing the component’s DOM . Even if it’s not the most recommended way it might occur that you need to access a DOM element from the script tag. In which case the shortcut this.document will gain you access to the DOM, wether it’s the Shadow DOM (default) or you toggled to Light DOM (overriding). this.document has all the native methods you may expect from a document such as querySelector, getElementById, querySelectorAll… . export default class extends Lego { init() { console.log(this.document.querySelectorAll('a')) } } . ",
"url": "/v1/usage-web-components/script-tag/#script-extend-tag",
"relUrl": "/v1/usage-web-components/script-tag/#script-extend-tag"
},"15": {
"doc": "Insert JavaScript in a Web-Component",
"title": "Insert JavaScript in a Web-Component",
"content": " ",
"url": "/v1/usage-web-components/script-tag/",
"relUrl": "/v1/usage-web-components/script-tag/"
},"16": {
"doc": "Naming convention for Web-Components",
"title": "Naming convention for Web-Components",
"content": "The name of the file will be the name of the component. Example: components/x-button.html will create <x-button> component. However in some cases you may want to give your component a different name than the file. To do so, you should give a name attribute in your <template> tag. Example: . components/x-button.html: . <template name=\"my-super-button\"></template> . Will make <my-super-button> component available. Note that because it builds native web-components, the naming convention must respect the ones from the standards (lowercase, with a dash in the name, starting with a letter, …) . ",
"url": "/v1/naming-components/",
"relUrl": "/v1/naming-components/"
},"17": {
"doc": "Compile Web-Components to JavaScript",
"title": "Compile Web-Components to JavaScript",
"content": "Compiling Lego component is built-in with no extra installation; pretty straighforward. npx lego [-w] [source_path] [target_path] . | -w: watching for changes in components and recreating | source_path: (default: ./bricks) either a file or a directory (relative or absolute) where you write your HTML components. If it’s a directory, it will recursively read all the .html files and compile them into the target_file. | target_path: (default: ./dist) the path (relative or absolute) where your JS components will be generated. That folder will be created and contain all the components. | . Therefore npx lego would compile the source_path files or folder (recursively) into target_file_path js file using lego.min.js (from ./bricks to ./dist by default). As mentioned before, when developing you probably want to watch for changes with the -w option: npx lego -w <source_path> <target_file_path> . ",
"url": "/v1/compile-components/",
"relUrl": "/v1/compile-components/"
},"18": {
"doc": "Configuring compilation for Web-Components",
"title": "Setup a Custom Configuration File",
"content": "Create a lego.config.js file at the root of your project with the following: . export default { // Your custom settings here } . This file will override the default config.js settings when declared. If your /lego.config.js file is not found, please ensure to have \"type\": \"module\" in your package.json file in order to read .js files as modules. ⚠️ Missing lego.config.js file, building with defaults. If reading in the console, it means the /lego.config.js was not found in the root folder of the project from where the compiler is called. It’s very fine if you don’t need to customize configuration and run with defaults. ",
"url": "/v1/configuring-components/#setup-a-custom-configuration-file",
"relUrl": "/v1/configuring-components/#setup-a-custom-configuration-file"
},"19": {
"doc": "Configuring compilation for Web-Components",
"title": "Configuring on compile time",
"content": "Passing parameters in the CLI will override default parameters and custom configuration. The command line accepts the following parameters: npx lego <sourceDir> <destDir> <options>. The only option for now is -w (stading for the watch config property). ",
"url": "/v1/configuring-components/#configuring-on-compile-time",
"relUrl": "/v1/configuring-components/#configuring-on-compile-time"
},"20": {
"doc": "Configuring compilation for Web-Components",
"title": "Configuring compilation for Web-Components",
"content": "The compiler can take serveral parameters: sourceDir, destDist, watch… . These will allow you to fine grain your configuration when compiling. The full list of parameters is available in the compiler config. You should see that file to know the exhaustive list of parameters and what they do. You can either setup each of these values from a custom config file or directly from the command line arguments. ",
"url": "/v1/configuring-components/",
"relUrl": "/v1/configuring-components/"
},"21": {
"doc": "Full Example of Web-Components",
"title": "Full Example of Web-Components",
"content": "Let’s write a web-component that: . | displays the full name of a user | shows a welcome text and the user | list all user’s favorite fruit | toggles user registration | . bricks/user-profile.html . <script> const state = { registered: false, firstName: 'John', lastName: 'Doe', fruits: [{ name: 'Apple', icon: '🍎' }, { name: 'Pineapple', icon: '🍍' }] } function register() { render({ registered: confirm('You are about to register…') }) } </script> <template> <h1>${ state.firstName } ${ state.lastName }'s profile</h1> <p>Welcome ${ state.firstName }!</p> <section :if=\"state.fruits.length\"> <h3>The best ${ state.fruits.length } fruit you like:</h3> <ul> <li :for=\"fruit in state.fruits\">${ fruit.name } ${ fruit.icon }</li> </ul> </section> <p :if=\"state.registered\">You are registered!</p> <button @click=\"register\">Register now</button> </template> . Compile this component: npx lego bricks . Then include it in your page: . index.html . <user-profile></user-profile> <script src=\"./dist/index.js\" type=\"module\"></script> . Run your web server and see your little app! . When developing you may want to automatically watch files changes. In that case pass the -w flag: npx lego -w bricks . Tip: you probably want to store this task with a shortcut like npm run watch. To do so just add \"watch\": \"lego -w bricks\" in you package.json scripts. ",
"url": "/v1/advanced-components/",
"relUrl": "/v1/advanced-components/"
},"22": {
"doc": "Testing Web-Components",
"title": "Running tests ",
"content": "Just install node dev dependencies (npm install) and run the tests (npm test). ",
"url": "/v1/testing-components/#running-tests-",
"relUrl": "/v1/testing-components/#running-tests-"
},"23": {
"doc": "Testing Web-Components",
"title": "Testing Web-Components",
"content": " ",
"url": "/v1/testing-components/",
"relUrl": "/v1/testing-components/"
},"24": {
"doc": "Understanding Web-Components",
"title": "Understanding Web-Components",
"content": "Native web-components . Because Lego is actual native web-components, all its native possibilities (like slots), :host and whatever exists or will exist are on board. Browser compatibility . Lego is based on native customElements. Support for customElement is spreading and shall increase in time. When building a web-app you may have control of the browsers. If you’re building a more general website you may need to increase the overall browser compatibility and install the custom-element polyfill. Dependencies . It is still fully compatible with native custom elements. No magic behind the scene, no complexity, just a couple of useful methods to write native web-components easier. Using a compiled component has no dependency, nothing extra injected in the browser. ",
"url": "/v1/advanced-webcomponents/",
"relUrl": "/v1/advanced-webcomponents/"
},"25": {
"doc": "Native Web-Components Library",
"title": "Native Web-Components Library",
"content": "LEGO (Lightweight Embedded Gluten-free Objects) is a library for writing fast ♻️ reactive, 📦 scoped and predictable 🏡 native web-components in HTML/CSS/JS, that are easy to digest 🌱 for your browser. Example (my-example.html): . <template> <p>Hey Joe</p> </template> <style> p { color: chocolate } </style> . These are native HTML elements with Shadow DOM, slots and all native features from the official specs. Lego is: . | 👙 Minimalist: ~74~ 61 lines of readable code in its core (non-optimised, uncompressed, no cheating). | 🌱 Low dependency: its single third-party is the minimalist Petit-Dom which itself has no dependency | ♻️ Reactive: updating the state recalculate the Virtual Dom when needed | 🚀 fast: using virtual dom through a thin layer makes it close to bare-metal | 💧 Simple: that’s Vanilla, there isn’t much to know, it’s a raw class to extend; no magic ✨ | 🏡 Native: webcomponents are actual native webcomponents, you benefit from all the today’s and tomorrow’s possibilites (slot, encapsulation, …) | 🦺 Safe: because it has no third-party dependency and is fully based on browser features, it’s secured and upgraded via your browser. | . Lego is not (and will never be): . | 🏯 A full bloated frontend framework with built-in routing. Others do it well. | 🏗 A website builder with buit-in SSR or similar complexities. | 🔐 An HTML replacement that locks you into a specific technology. | 🧓 An old browsers or IE compatible library (you may try webcomponent polyfills if you feel wild). | . View the demo and their source 🧪. Lego is inspired from the native Web-Component spec and Riot. It’s just much lighter with simplicity, a source code that is readable for a regular human which makes it accessible to hack, tweak and maintain in the loooong term. The core lib is only 61 LOC! Lego is as light as 3Kb for the full bundle! . No Babel transpiler, no Parcel, no Webpack… it just works out of the box. Demo: view in action . ",
"url": "/v1/",
"relUrl": "/v1/"
},"26": {
"doc": "Build Native Web-Components",
"title": "Quick start",
"content": "Installation . If you don’t have a package.json file yet, initialize first with npm init (or yarn init). Install the compiler with npm i @polight/lego (or yarn add @polight/lego). Basic Example . This is the file tree we will need for this example: . index.html |- bricks/ |- hello-world.html → The HTML you typed . Hello World . Create a file called bricks/hello-world.html: . <script> const state = { name: \"World!\" } } </script> <template> <p>Hello ${ state.name }</p> </template> . Compile with npx lego (or yarn lego) . And use you component in your /index.html: . <script src=\"./dist/index.js\" type=\"module\"></script> <hello-world></hello-world> . Run a local web server, eg: npx sirv-cli and open http://localhost:5000. ",
"url": "/v2/getting-started/#quick-start",
"relUrl": "/v2/getting-started/#quick-start"
},"27": {
"doc": "Build Native Web-Components",
"title": "Let’s get a step back",
"content": "What did just happen? . Here’s what you just did with this simple code: . | you created a native HTML element called hello-world by creating bricks/hello-world.html | you made it react with a name state property | you imported all components from ./dist/index.js (well, only 1 for now) | you used the HTML element <hello-world></hello-world> | . No magic 🪄 here, just a couple of default configuration that you can override. You website is ready to be published on any static host, even Github Pages. ",
"url": "/v2/getting-started/#lets-get-a-step-back",
"relUrl": "/v2/getting-started/#lets-get-a-step-back"
},"28": {
"doc": "Build Native Web-Components",
"title": "Build Native Web-Components",
"content": "Lego requires npm or yarn and node. By default Lego compiles HTML components from the HTML files within the /bricks folder. Create the folder to host your future components: mkdir bricks. ",
"url": "/v2/getting-started/",
"relUrl": "/v2/getting-started/"
},"29": {
"doc": "Using Native Web-Components",
"title": "Usage of Lego web-components",
"content": "A web-component can optionally have 3 parts: some HTML in a <template> tag, some JavaScript in a <script> tag and some CSS in a <style> tag. You can make a web-component for muliple reasons. If you just want to re-use a piece of HTML, the <template> tag is all you need. If you want to polish it’s look 💅, <style> is your friend. Bonus: it’s fully scoped with no leaking out of context. When some user interaction or reactiveness is demanded, <script> is going to be the guy. ",
"url": "/v2/usage-web-components/#usage-of-lego-web-components",
"relUrl": "/v2/usage-web-components/#usage-of-lego-web-components"
},"30": {
"doc": "Using Native Web-Components",
"title": "Using Native Web-Components",
"content": ". | Usage of Lego web-components | . ",
"url": "/v2/usage-web-components/",
"relUrl": "/v2/usage-web-components/"
},"31": {
"doc": "Template Tag to write HTML in Web-Components",
"title": "Template Tag to write HTML in Web-Components",
"content": "<template> tag . An HTML content is written within a <template> tag. It’s just basic HTML augmented with a little of superpowers 🦸. Let’s call these superpowers “directives”. You may easily detect them as they are prefixed with : or @. Only 4 directives to know: . | :if to display a tag based on a condition | :for to repeat a tag | : to evaluate a string | @ to bind an event | . Note that :if and :for attributes, when used in the same tag should be used with an order in mind: <a :if=\"user\" :for=\"user in state.users\"> won’t work, but <a :if=\"state.users.length\" :for=\"user in state.users\"> will first evaluate if the users array has items, or <a :for=\"user in users\" :if=\"user\"> will check that each individual user has a value. <a :if=\"state.isAdmin\" :for=\"user in state.users\"> won’t loop at all if isAdmin is false. ",
"url": "/v2/usage-web-components/template/",
"relUrl": "/v2/usage-web-components/template/"
},"32": {
"doc": "Using Condition in Web-Components",
"title": "Using Condition in Web-Components",
"content": ":if Directive . Conditionally display a tag and its descendants. Example: <p :if=\"state.count < 5\">Less than 5</p> will be displayed if the condition is met. ",
"url": "/v2/usage-web-components/condition/",
"relUrl": "/v2/usage-web-components/condition/"
},"33": {
"doc": "Using loops in Web-Components",
"title": "Using loops in Web-Components",
"content": ":for Directive . Repeat a tag based on a property. The syntax is as follow: :for=\"item in state.items\". The item value will be available trough ${item} within the loop. If you need an incremental index i, use :for=\"item, i in state.items\". Example: <li :for=\"attendee in state.attendees\">${attendee}</li> with a state as this.state = { attendees: ['John', 'Mary'] } will display <li>John</li><li>Mary</li> . ",
"url": "/v2/usage-web-components/loop/",
"relUrl": "/v2/usage-web-components/loop/"
},"34": {
"doc": "Inserting Custom Attributes in Web-Components",
"title": "Inserting Custom Attributes in Web-Components",
"content": ": Custom Directive . A custom directive will interpret in JS whatever you pass as value. <script> function getUrl(id) { return `/user/${id}` } </script> <template> <a :href=\"getUrl('144')\">Visit Profile</a> </template> . outputs . <a href=\"/user/144\">Visit Profile</a> . Boolean attributes . Example: <input type=checkbox :checked=\"state.agreed\" :required=\"state.mustAgree\">. With the following state: const state = { agreed: false, mustAgree: true } would render <input type=checkbox required=\"required\">. ",
"url": "/v2/usage-web-components/custom-directive/",
"relUrl": "/v2/usage-web-components/custom-directive/"
},"35": {
"doc": "Bind an Event to a Web-Component",
"title": "Bind an Event to a Web-Component",
"content": "@ Directive for binding Events . <script> function sayHi(event) { const buttonName = event.target.name alert(`You clicked ${ buttonName } to says hi! 👋🏼`) } </script> <template> <button @click=\"sayHi\" name=\"the-button\">click</button> </template> . ",
"url": "/v2/usage-web-components/events/",
"relUrl": "/v2/usage-web-components/events/"
},"36": {
"doc": "Reactive Web-Components to Update HTML",
"title": "Reactive Web-Components to Update HTML",
"content": "Reactive Properties . The state is where the reactiveness takes place. declare a state object in the init() function with default values: . const state = { user: { firstname: 'John', lastname: 'Doe' }, status: \"Happy 😄\" } const title = \"This title is non-reactive\" . Displaying a state value is as simple as writing ${state.theValue} in your HTML. When you need your component to react, call the render() method with your updated state: . function updateStatus(event) { render({ status: \"Laughing 😂\" }) } . This will update your component only where needed. When state is just mutated, the changed(changedProps) is called. This changed() method is called before (re-)rendering. ",
"url": "/v2/usage-web-components/reactive/",
"relUrl": "/v2/usage-web-components/reactive/"
},"37": {
"doc": "Pass Attributes to Web-Components",
"title": "Pass Attributes to Web-Components",
"content": "Component Attributes . Attributes declared on the components will be all be accessible through the state. If the property is initialized in the this.state, the attribute will be reactive: . <x-user status=\"thinking 🤔\"><x-user> . status will therefore be reactive and the thinking 🤔 attribute value will overwrite the Happy 😄 default status. ⚠️ A property that is not declared in the state won’t be reactive. These properties can be accessed through this.getAttribute() from within the component. After all, these components are just native! 🏡 . Slots . Slots are part of the native web-component. Because Lego builds native web-components, you can use the standard slots as documented. Example: . index.html . <user-profile> <span>This user is in Paris</span> <user-profile> . bricks/user-profile.html . <template> <h1>User profile</h1> <p>important information: <slot></slot></p> </template> . Will write …<p>important information: <span>This user is in Paris</span></p> . See more advanced examples. Reactive CSS Within <style> . CSS is much more fun when it’s scoped. Here it come with the web-components. Here again, no trick, just the full power of web-components and scoping styles. Well, you should know that the css is reactive too! 😲 . Writing CSS is as easy as . <script> const state = { fontScale: 1 } </script> <template> <h1>Bonjour!</h1> </template> <style> :host { font-size: ${state.fontScale}rem; } h1 { padding: 1rem; text-align: center; } </style> . Host . :host is a native selector for web-components. It allows to select the current component itself. Variables . You can use variables in your CSS just like in your templates. Example: . <script> const state = { color: '#357' } </script> <template> <h1>Bonjour<h1> </template> <style> h1 { color: ${ state.color }; } </style> . will apply the #357 color onto h1. ",
"url": "/v2/usage-web-components/attributes/",
"relUrl": "/v2/usage-web-components/attributes/"
},"38": {
"doc": "Using slots to Insert Elements in Web-Components",
"title": "Using slots to Insert Elements in Web-Components",
"content": "Slots . Slots are part of the native web-component. Because Lego builds native web-components, you can use the standard slots as documented. Example: . index.html . <user-profile> <span>This user is in Paris</span> <user-profile> . bricks/user-profile.html . <template> <h1>User profile</h1> <p>important information: <slot></slot></p> </template> . Will write …<p>important information: <span>This user is in Paris</span></p> . See more advanced examples. ",
"url": "/v2/usage-web-components/slots/",
"relUrl": "/v2/usage-web-components/slots/"
},"39": {
"doc": "Using Reactive CSS to Update Styles in Web-Components",
"title": "Using Reactive CSS to Update Styles in Web-Components",
"content": "Reactive CSS <style> . CSS is much more fun when it’s scoped. Here it come with the web-components. Here again, no trick, just the full power of web-components and scoping styles. Well, you should know that the css is reactive too! 😲 . Writing CSS is as easy as . <template> <h1>Bonjour!</h1> </template> <script> export default class extends Lego { init() { this.state = { fontScale: 1 } } } </script> <style> :host { font-size: ${state.fontScale}rem; } h1 { padding: 1rem; text-align: center; } </style> . Host . :host is a native selector for web-components. It allows to select the current component itself. Variables . You can use variables in your CSS just like in your templates. Example: . <template> <h1>Bonjour<h1> </template> <script> export default class extends Lego { init() { this.state = { color: '#357' } } } </script> <style> h1 { color: ${ state.color }; } </style> . will apply the #357 color onto h1. ",
"url": "/v2/usage-web-components/reactive-css/",
"relUrl": "/v2/usage-web-components/reactive-css/"
},"40": {
"doc": "Insert JavaScript in a Web-Component",
"title": "<script extend> tag",
"content": "The “script extend” tag is has a special behavior. You will create a class extending the component, that’s how you extend your full component with advanced script. To do so extend the Lego class, that’s a naming convention: . export default class extends Lego { … } . From there you can catch connected() events, changed() when the state is updated, override setAttributes() and all other Lego or HTMLElement properties. It’s also a great place to define custom events or custom methods for your component that are accessible from the outside: . /bricks/my-element.html . <script extend> export default class extends Lego { getStatus() { return `you are requesting status of ${ this.nodeName }`) } connected() { console.info('the component is connected to the dom') } } </script> . /bricks/index.html . <my-element id=\"elem\"></my-element> <script> console.debug(document.querySelector('#elem').getStatus()) </script> . Accessing the component’s DOM . Even if it’s not the most recommended way it might occur that you need to access a DOM element from the script tag. In which case the shortcut this.document will gain you access to the DOM, wether it’s the Shadow DOM (default) or you toggled to Light DOM (overriding). this.document has all the native methods you may expect from a document such as querySelector, getElementById, querySelectorAll… . export default class extends Lego { init() { console.log(this.document.querySelectorAll('a')) } } . ",
"url": "/v2/usage-web-components/script-tag/#script-extend-tag",
"relUrl": "/v2/usage-web-components/script-tag/#script-extend-tag"
},"41": {
"doc": "Insert JavaScript in a Web-Component",
"title": "Insert JavaScript in a Web-Component",
"content": " ",
"url": "/v2/usage-web-components/script-tag/",
"relUrl": "/v2/usage-web-components/script-tag/"
},"42": {
"doc": "Naming convention for Web-Components",
"title": "Naming convention for Web-Components",
"content": "The name of the file will be the name of the component. Example: components/x-button.html will create <x-button> component. However in some cases you may want to give your component a different name than the file. To do so, you should give a name attribute in your <template> tag. Example: . components/x-button.html: . <template name=\"my-super-button\"></template> . Will make <my-super-button> component available. Note that because it builds native web-components, the naming convention must respect the ones from the standards (lowercase, with a dash in the name, starting with a letter, …) . ",
"url": "/v2/naming-components/",
"relUrl": "/v2/naming-components/"
},"43": {
"doc": "Compile Web-Components to JavaScript",
"title": "Compile Web-Components to JavaScript",
"content": "Compiling Lego component is built-in with no extra installation; pretty straighforward. npx lego [-w] [source_path] [target_path] . | -w: watching for changes in components and recreating | source_path: (default: ./bricks) either a file or a directory (relative or absolute) where you write your HTML components. If it’s a directory, it will recursively read all the .html files and compile them into the target_file. | target_path: (default: ./dist) the path (relative or absolute) where your JS components will be generated. That folder will be created and contain all the components. | . Therefore npx lego would compile the source_path files or folder (recursively) into target_file_path js file using lego.min.js (from ./bricks to ./dist by default). As mentioned before, when developing you probably want to watch for changes with the -w option: npx lego -w <source_path> <target_file_path> . ",
"url": "/v2/compile-components/",
"relUrl": "/v2/compile-components/"
},"44": {
"doc": "Configuring compilation for Web-Components",
"title": "Setup a Custom Configuration File",
"content": "Create a lego.config.js file at the root of your project with the following: . export default { // Your custom settings here } . This file will override the default config.js settings when declared. If your /lego.config.js file is not found, please ensure to have \"type\": \"module\" in your package.json file in order to read .js files as modules. ⚠️ Missing lego.config.js file, building with defaults. If reading in the console, it means the /lego.config.js was not found in the root folder of the project from where the compiler is called. It’s very fine if you don’t need to customize configuration and run with defaults. ",
"url": "/v2/configuring-components/#setup-a-custom-configuration-file",
"relUrl": "/v2/configuring-components/#setup-a-custom-configuration-file"
},"45": {
"doc": "Configuring compilation for Web-Components",
"title": "Configuring on compile time",
"content": "Passing parameters in the CLI will override default parameters and custom configuration. The command line accepts the following parameters: npx lego <sourceDir> <destDir> <options>. The only option for now is -w (stading for the watch config property). ",
"url": "/v2/configuring-components/#configuring-on-compile-time",
"relUrl": "/v2/configuring-components/#configuring-on-compile-time"
},"46": {
"doc": "Configuring compilation for Web-Components",
"title": "Configuring compilation for Web-Components",
"content": "The compiler can take serveral parameters: sourceDir, destDist, watch… . These will allow you to fine grain your configuration when compiling. The full list of parameters is available in the compiler config. You should see that file to know the exhaustive list of parameters and what they do. You can either setup each of these values from a custom config file or directly from the command line arguments. ",
"url": "/v2/configuring-components/",
"relUrl": "/v2/configuring-components/"
},"47": {
"doc": "Full Example of Web-Components",
"title": "Full Example of Web-Components",
"content": "Let’s write a web-component that: . | displays the full name of a user | shows a welcome text and the user | list all user’s favorite fruit | toggles user registration | . bricks/user-profile.html . <script> const state = { registered: false, firstName: 'John', lastName: 'Doe', fruits: [{ name: 'Apple', icon: '🍎' }, { name: 'Pineapple', icon: '🍍' }] } function register() { render({ registered: confirm('You are about to register…') }) } </script> <template> <h1>${ state.firstName } ${ state.lastName }'s profile</h1> <p>Welcome ${ state.firstName }!</p> <section :if=\"state.fruits.length\"> <h3>The best ${ state.fruits.length } fruit you like:</h3> <ul> <li :for=\"fruit in state.fruits\">${ fruit.name } ${ fruit.icon }</li> </ul> </section> <p :if=\"state.registered\">You are registered!</p> <button @click=\"register\">Register now</button> </template> . Compile this component: npx lego bricks . Then include it in your page: . index.html . <user-profile></user-profile> <script src=\"./dist/index.js\" type=\"module\"></script> . Run your web server and see your little app! . When developing you may want to automatically watch files changes. In that case pass the -w flag: npx lego -w bricks . Tip: you probably want to store this task with a shortcut like npm run watch. To do so just add \"watch\": \"lego -w bricks\" in you package.json scripts. ",
"url": "/v2/advanced-components/",
"relUrl": "/v2/advanced-components/"
},"48": {
"doc": "Testing Web-Components",
"title": "Running tests ",
"content": "Just install node dev dependencies (npm install) and run the tests (npm test). ",
"url": "/v2/testing-components/#running-tests-",
"relUrl": "/v2/testing-components/#running-tests-"
},"49": {
"doc": "Testing Web-Components",
"title": "Testing Web-Components",
"content": " ",
"url": "/v2/testing-components/",
"relUrl": "/v2/testing-components/"
},"50": {
"doc": "Understanding Web-Components",
"title": "Understanding Web-Components",
"content": "Native web-components . Because Lego is actual native web-components, all its native possibilities (like slots), :host and whatever exists or will exist are on board. Browser compatibility . Lego is based on native customElements. Support for customElement is spreading and shall increase in time. When building a web-app you may have control of the browsers. If you’re building a more general website you may need to increase the overall browser compatibility and install the custom-element polyfill. Dependencies . It is still fully compatible with native custom elements. No magic behind the scene, no complexity, just a couple of useful methods to write native web-components easier. Using a compiled component has no dependency, nothing extra injected in the browser. ",
"url": "/v2/advanced-webcomponents/",
"relUrl": "/v2/advanced-webcomponents/"
},"51": {
"doc": "Native Web-Components Library",
"title": "Native Web-Components Library",
"content": "LEGO (Lightweight Embedded Gluten-free Objects) is a library for writing fast ♻️ reactive, 📦 scoped and predictable 🏡 native web-components in HTML/CSS/JS, that are easy to digest 🌱 for your browser. Example (my-example.html): . <template> <p>Hey Joe</p> </template> <style> p { color: chocolate } </style> . These are native HTML elements with Shadow DOM, slots and all native features from the official specs. Lego is: . | 👙 Minimalist: ~74~ 61 lines of readable code in its core (non-optimised, uncompressed, no cheating). | 🌱 Low dependency: its single third-party is the minimalist Petit-Dom which itself has no dependency | ♻️ Reactive: updating the state recalculate the Virtual Dom when needed | 🚀 fast: using virtual dom through a thin layer makes it close to bare-metal | 💧 Simple: that’s Vanilla, there isn’t much to know, it’s a raw class to extend; no magic ✨ | 🏡 Native: webcomponents are actual native webcomponents, you benefit from all the today’s and tomorrow’s possibilites (slot, encapsulation, …) | 🦺 Safe: because it has no third-party dependency and is fully based on browser features, it’s secured and upgraded via your browser. | . Lego is not (and will never be): . | 🏯 A full bloated frontend framework with built-in routing. Others do it well. | 🏗 A website builder with buit-in SSR or similar complexities. | 🔐 An HTML replacement that locks you into a specific technology. | 🧓 An old browsers or IE compatible library (you may try webcomponent polyfills if you feel wild). | . View the demo and their source 🧪. Lego is inspired from the native Web-Component spec and Riot. It’s just much lighter with simplicity, a source code that is readable for a regular human which makes it accessible to hack, tweak and maintain in the loooong term. The core lib is only 61 LOC! Lego is as light as 3Kb for the full bundle! . No Babel transpiler, no Parcel, no Webpack… it just works out of the box. Demo: view in action . ",
"url": "/v2/",
"relUrl": "/v2/"
}
}