Developer Insights
Join millions of viewers! Our engineers craft human-written articles solving real-world problems weekly. Enjoy fresh technical content and numerous interviews featuring modern web advancements with industry leaders and open-source authors.
A Tale of Form Autofill, LitElement and the Shadow DOM
Many web applications utilize forms in places be it for logging in, making payments, or editing a user profile. As a user of web applications, you have probably noticed that the browser is able to autofill in certain fields when a form appears so that you don't have to do it yourself. If you've ever written an application in Lit though, you may have noticed that this doesn't always work as expected. The Problem I was working on a frontend project utilizing Lit and had to implement a login form. In essence these aren’t very complicated on the frontend side of life. You just need to define a form, put some input elements inside of it with the correct type attributes assigned to it, then you hook the form up to your backend, API, or whatever you need to call to authenticate by adding a submit handler. However, there was an issue. The autocomplete doesn’t appear to be working as expected. Only the username field was being filled, but not the password. When this happened, I made sure to check documentation sites such as MDN and looked at examples. But I couldn’t find any differences between theirs and mine. At some point, I prepared a minimal reproducible example without Lit, and I was able to get the form working fine, so it had to do something with my usage of Lit. After doing a little bit of research and some testing, I found out this happened because Lit relies very heavily on something known as the Shadow DOM. I don’t believe the Shadow DOM is necessarily supposed to break this functionality. But for most major browsers, it doesn’t play nice with autocomplete for the time being. I experienced slightly different behavior in all browsers, and the autocomplete even worked under Shadow DOM with Firefox in the Lit app I was working on. The solution I ended up settling on was ensuring the form was contained inside of the Light DOM instead of the Shadow DOM, whilst also allowing the Shadow DOM to continue to be used in places where autofillable forms are not present. In this article I will show you how to implement this solution, and how to deal with any problems that might arise from it. Shadow DOM vs. Light DOM The Shadow DOM is a feature that provides a way to encapsulate your components and prevent unrelated code and components from affecting them in undesired ways. Specifically, it allows for a way to prevent outside CSS from affecting your components and vice versa by scoping them to a specific shadow root. When it comes to the Light DOM, even if you’ve never heard of the term, you’ve probably used it. If you’ve ever worked on any website before, and interacted with the standard DOM tree, that is the Light DOM. The Light DOM, and any Shadow DOMs under it for that matter, can contain Shadow DOMs inside of them attached to elements. When you add a Lit component to a page, a shadow root will get attached to it that will contain its subelements, and prevent CSS from outside of that DOM from affecting it. Using Light DOM with Certain Web Components By default, Lit attaches a shadow root to all custom elements that extend from LitElement. However, web components don’t actually require a shadow root to function. We can do away with the shadow root by overriding the createRenderRoot method, and returning the web component itself: ` Although we can just put this method in any element we want exposed into the Light DOM. We can also make a new component called LightElement that overrides this method that we can extend from instead of LitElement on our own components. This will be useful later when we tackle another problem. Uh oh, where did my CSS styling and slots go? The issue with not using a shadow root is Lit has no way to encapsulate your component stylesheets anymore. As a result, your light components will now inherit styles from the root that they are contained in. For example, if your components are directly in the body of the page, then they will inherit all global styles on the page. Similarly when your light components are inside of a shadow root, they will inherit any styles attached to that shadow root. To resolve this issue, one could simply add style tags to the HTML template returned in the render() method, and accept that other stylesheets in the same root could affect your components. You can use naming conventions such as BEM for your CSS classes to mitigate this for the most part. Although this does work and is a very pragmatic solution, this solution does pollute the DOM with multiple duplicate stylesheets if more than one instance of your component is added to the DOM. Now, with the CSS problem solved, you can now have a functional Lit web component with form autofill for passwords and other autofillable data! You can view an example using this solution here. A Better Approach using Adopted Stylesheets For a login page where only one instance of the component is in the DOM tree at any given point, the aforementioned solution is not a problem at all. However, this can become a problem if whatever element you need to use the Light DOM with is used in lots of places or repeated many times on a page. An example of this would be a custom input element in a table that contains hundreds of rows. This can potentially cause performance issues, and also pollute the CSS inspector in your devtools resulting in a suboptimal experience both for users and yourself. The better, though still imperfect, way to work around this problem is to use the adopted stylesheets feature to attach stylesheets related to the web component to the root it is connected in, and reuse that same stylesheet across all instances of the node. Below is a function that tracks stylesheets using an id and injects them in the root node of the passed in element. Do note that, with this approach, it is still possible for your component’s styles to leak to other components within the same root. And like I advised earlier, you will need to take that into consideration when writing your styles. ` This solution works for most browsers, and a fallback is included for Safari as it doesn’t support adoptedStylesheets at the time of writing this article. For Safari we inject de-duplicated style elements at the root. This accomplishes the same result effectively. Let’s go over the evictDisconnectedRoots function that was called inside of the injection function. We need to ensure we clean up global state since the injection function relies on it to keep duplication to a minimum. Our global state holds references to document nodes and shadow roots that may no longer exist in the DOM. We want these to get cleaned up so as to not leak memory. Thankfully, this is easy to iterate through and check because of the isConnected property on nodes. ` Now we need to get our Lit component to use our new style injection function. This can be done by modifying our LightElement component, and having it iterate over its statically defined stylesheets and inject them. Since our injection function contains the de-duplication logic itself, we don’t need to concern ourselves with that here. ` With all that you should be able to get an autocompletable form just like the previous example. The full example using the adopted stylesheets approach can be found here. Conclusion I hope this article was helpful for helping you figure out how to implement autofillable forms in Lit. Both examples can be viewed in our blog demos repository. The example using basic style tags can be found here, and the one using adopted stylesheets can be found here....
Jun 7, 2023
6 mins
Building a Lightweight Component with Lit
Component-based apps make it much easier to build independent components and share them across projects. With broken-down units as small as a button or user interactions, project iterations tend to become faster and more developer friendly. For this article, we will use Lit to build web components for our front-end apps. What is Lit? According to the docs, Lit is a simple library for building fast, lightweight web components. Using Lit, you can build highly reusable components with the following features: - Native component for the browser aka Web Component - Framework agnostic, sharable and usable across multiple web frameworks - Lightweight, not requiring too much JavaScript code to implement - Flexible and can easily be plugged into any future project and still work as expected. Prerequisites To follow along with this article, I recommend you have: - Basic knowledge of JavaScript and a frontend framework (React, Angular or Vue) - Code Editor For this, we will be using the Lit JavaScript starter kit. Clone the repo to your local machine ` And change directory ` Install dependencies. ` Open the project with a code editor, and navigate to the file list-element.js: ` Our web component ListElememt is a class that extends to the LitElement base class with the styles() and property() methods. The styles() method returns the CSS for the component that uses the css method imported from Lit to define component-scoped CSS in a template literal. The properties() method returns the properties which expose the component's reactive variables. We declare an internal state of todoList to hold the list of todos. Then, we assign default values to properties in the constructor method. todoList is an empty array. The render() method returns the view using the html imported from Lit to define the html elements in a template literal. In the rendered html, we added an input element with id of fullname and a button with a click event triggering the custom method _pushTodo to push new Todo to the todoList array. Then, we map through the list of todos with map directives imported from Lit and attach a button to each item with an event to remove the item when clicked, calling a custom method _removeTodo that filters through the array, and returns items that satisfy our condition. The getter method _input() returns the input element we created to give access to the input value so we can pass it to the _pushTodo method. Now, to render the component, we will modify the index.html head section. ` We will also need to modify the body element of our index.html file. ` Now, run the app to see our modification, run: ` From the browser, navigate to localhost:8000, and you should see the element rendered below. Benefits of Lit Components Now we have a running app with a reusable component. Let's explore the Lit benefits of this component, and what differentiates it from other tools for building components. Native: Lit is built on top of the Web Components standards and you are able to extend just what you need for productivity: reactivity, declarative templates, and a handful of thoughtful features to reduce boilerplate and make your job easier. In our ListElement code, we defined the custom HTML element with window.customElements.define which defines and registers a new custom element to the browser DOM and associates it with an element name list-element, making our component native. Every Lit component is built with web platform evolution in mind. Fast and Small: Lit has a 5 kb compressed size and a minified bundle which allows your application to load faster without the need to rebuild a virtual tree (No virtual DOM). Lit batches updates to maximize performance and efficiency. Setting multiple properties at once triggers only one update, performed asynchronously at microtask timing. Interoperable & future-ready: Every Lit component is a native web component with the superpower of interoperability. Web components work anywhere you use HTML with any framework, or none at all. This makes Lit ideal for building shareable components, design systems, or maintainable, future-ready sites and apps. Here is how you can quickly make our ListElement component usable and shareable across any project built with any framework or without one. For the dev/index.html head, we simply imported the JavaScript module of list-element.js and quickly add the custom HTML element to the body: ` Reactivity with Lit: Lit components receive input and store their state as JavaScript class fields or properties. Reactive properties are properties that can trigger the reactive update cycle when changed, re-rendering the component, and optionally be read or written to attributes. ` All JavaScript properties in Lit are defined inside this properties object, and then we used the constructor method in our App component class to set an initial value for the properties we created. Events: In addition to the standard addEventListener API, Lit introduces a declarative way to add event listeners. You will notice we used @ expressions in our template to add event listeners to elements in our component's template. We added the @click event and bind it into the template. Declarative event listeners are added when the template is rendered. ` Lifecycle Lit components use the standard custom element lifecycle methods. In addition, Lit introduces a reactive update cycle that renders changes to DOM when reactive properties change. Lit components are standard custom elements and inherit the custom element lifecycle methods. In our ListElement class, we have the constructor() method which is called when an element is created. Also, it’s invoked when an existing element is upgraded, which happens when the definition for a custom element is loaded after the element is already in the DOM. You will notice in our _pushTodo() method we initiated a Lifecycle update by calling requestUpdate() method to perform an update immediately. Lit saves any properties already set on the element. This ensures values set before the upgrade are maintained and correctly override defaults set by the component. This is so we can push new items to the array and immediately re-render the component. Conclusion Congratulations! You`ve learned how to build lightweight components with Lit.dev, and explore some of the benefits of using native web components which can be used across frameworks and non-frameworks apps. What is the exciting thing you will be building with Lit? Let us know on Twitter!...
Oct 5, 2022
5 mins
How to integrate Web Components using Lit in Angular
In previous posts, I explained how to create projects in Lit and TypeScript from scratch. Also, I covered different topics about Web Components, and Single-Page Applications, using them. In this tutorial, I'll explain the needed steps to integrate these Web Components in Angular. Spoiler: You can find the source code of a demo project at the end. Project Setup Prerequisites You'll need to have installed the following tools in your local environment: - Node.js. Preferably the latest LTS version. - A package manager. You can use either NPM or Yarn. This tutorial will use NPM. Creating the Angular Project Let's create a project from scratch using the Angular CLI tool. ` This command will initialize a base project using some configuration options: - --routing. It will create a routing module. - --prefix corp. It defines a prefix to be applied to the selectors for created components(corp in this case). The default value is app. - --style css. The file extension for the styling files. - --skip-tests. It avoids the generations of the .spec.ts files, which are used for testing. Install Lit > Lit is a simple library for building fast, lightweight web components. Lit is available via npm, let's install it as a new dependency for the current project. ` Find more information about Lit here. Install Web Components Polyfills There are several ways to install the Web Components polyfills. In this case, we'll install it using npm. ` Then you can use the webcomponents-loader.js, which allows loading a minimum polyfill bundle. Update the Angular Configuration You can load the polyfills using a tag into the index.html file. However, the _Angular way_ to do it is by adding a new asset and script configurations into your angular.json file as follows: ` Both input and output properties must be relative to the project's root path. The same applies to the script imported. Creating your Web Components using Lit The project setup has been completed, and now it's time to create our first web component using Lit. Let's create an src/web-components/card-user folder, and then create two files: card-user.ts and user.ts. The user.ts file will define a common model used by the Web Component implementation, and the Angular project: ` Next, let's define the TypeScript code for our Web component into card-user.ts file: ` The previous class defines a new _custom element_ as a brand new _widget_ for our project. - The @customElement decorator allows the component definition using a name for it: card-user. It is applied at the class level. - The static styles attribute defines the styles for the component using a tagged template literal (css). - The @property decorator, which allows declaring properties for the custom element in a readable way. - The render method returns the HTML content through a template literal (html). This function will be called any time the user property changes. You can read more about how to define a component using Lit here. Using Web Components in Angular Import the Web Component Before using any Web Component in an Angular component, we'll need to make sure to import its definition as follows. ` Use the Custom Element The next step is to use the brand-new custom element as part of any template. In this case, let's use it in our app.component.html file: ` Once you save these changes, you may find an error in your command-line interface (the place where you're running ng serve). ` Fortunately, the previous error message is significant enough to understand that we'll need to apply a change in the app.module.ts file, which is the main module of our application. ` The important part here is to import the CUSTOM_ELEMENTS_SCHEMA from the @angular/core package, and then use it in the schemas property. You can find more information about it here. Save your changes again, and the magic will happen :-) Using the Property Binding It is convenient to know that we can not only import external components in our application but also make use of the Property binding. To do that, let's define a user property in the app.component.ts file: ` Then, we can update the related template, and use the brackets notation to bind the property: ` Even better, you can create an array of users to be able to render them using other nice features from our favorite framework, such as the structural directive *ngFor. ` Using the Event Binding It's time to listen and respond to user actions through the _Event binding_ with Angular. As you saw before, the corp-user component is able to dispatch an edit event once the "Edit" button is clicked. Let's use the parentheses notation this time to bind a method: ` Finally, let's create the edit method in our component. ` The edit method receives a generic Event. However, the _Custom Element_ has sent a User object through the CustomEvent detail. Then, we can use the as syntax operator from TypeScript and get access to it using the detail property. The next screenshot shows the results in the browser's console. Source Code of the Project Find the complete project in this GitHub repository: angular-lit-web-components. Do not forget to give it a star ⭐️ and play around with the code. Feel free to reach out on Twitter if you have any questions. Follow me on GitHub to see more about my work....
Oct 14, 2021
5 mins
Double Click: Try Out the New Releases for jQuery UI & Lit
Welcome to the Double Click! This is the weekly blog series that shines a spotlight on emerging technologies, technological concepts, and community projects that enrich the JavaScript Ecosystem! This week, I’m diving into some updates from two web development technologies that have recently seen updated releases: jQuery UI & Lit. jQuery 1.13.0-rc.2 jQuery UI is a popular JavaScript library that sees wide use across the web despite the technology not previously receiving an update in about five years. Omg! That’s why I’m thrilled to see jQuery UI receive some much needed love in the form of this 1.13.0-rc.2 release, which contains no breaking changes, but sort of polishes off some of its deprecated features to support wider use in modern user interfaces. The jQuery UI team has noted that it has struggled over the years to find reliable contributors, which may explain why it has taken five years to see any updated releases. However, the team notes that they presently don’t intend to significantly expand the framework, and that it will now enter a maintenance phase to simply ensure that it is compatible with future jQuery releases, and secure. Lit 2.0 Lit has gone through a number of changes with this most recent release which officially launched last week. They have a new logo, a new name (having previously been called "Lit Element”), a new npm, and a ton of new features. If you aren’t familiar with Lit, it is a library that simplifies and supercharges the process of building and implementing web components from Google. With this new release, the Lit team has slashed the size of the library to 6KB, just a fraction of the size of your average JavaScript framework, which increases its speed and performance. But this isn’t the only significant improvement to the technology as the Lit team has also introduced new features like a class-based API for directive authors, templating enhancements, and reactive controllers. But what most caught my attention was the significant improvements to the Lit site and documentation. Aside from undergoing some major UI transformations, the new Lit website also features detailed documentation that includes a sandbox where users can test out Lit 2.0’s newest features in the browser! What are you excited about lately? Make sure to share with me on twitter @ladyleet....
Oct 1, 2021
2 mins
Getting Started with Here Maps and Web Components using Lit
In the past months, I have been actively working on the development of geolocation-oriented solutions in web applications. My experience has been good so far, taking into account the availability of modern tools and libraries, with a wide range of features that even enable the use of interactive maps and location services. In this article, I'll explain how to integrate Here Maps through web components, using Lit and TypeScript, in just a few steps. Introduction Let's start by explaining the technologies that we will be integrating into this post, step by step. Lit Lit is the next-generation library for creating simple, fast, and lightweight web components. One of the benefits of using Lit is the power of interoperability, which means that your web components can be integrated within any framework, or can even be used on their own. This is possible since we're talking about native web components that can be rendered in any modern web browser. If you're interested in learning more about this technology, you can take a look at the LitElement Series that has been published in this blog. Here Maps Let's say your application requires real-time navigation, the creation of custom maps, or the ability to visualize datasets over a map. HERE Maps meet these requirements without too much effort. In fact, there is a Maps API for JavaScript, which can be used to build web applications using either JavaScript or TypeScript. Note Although this guide provides an API key for testing purposes only, you may need to register your app, and get your API Key to move forward with your applications. Creating the Project Project Scaffolding An easy way to initialize an application is through the project generator from the Open Web Components initiative. They provide a set of tools and guides to create a web components application, adding the testing, linting, and build support in the beginning. Let's create the project using a command-line interface ` Pay attention to the project structure that is generated. Also, take a look at your package.json file to review the dependencies and scripts that have been added. Update to Lit In case you generated a project based on LitElement, it shouldn't be complicated to replace dependencies with lit: - Install the last version of Lit ` - Uninstall LitElement and lit-html library ` Also, you can make sure to update the imports as follows to make it work: ` Next, make sure the preview of the application is working fine using the following command: ` Creating a Map Component Installing Here Maps Before creating a web component that will render a map, you are required to load the API code libraries in our index.html file: ` You can see HERE Maps API for JavaScript Modules for more information about each imported script. Since the initial project is based on TypeScript, we may need to install the type definitions for the HERE Maps API. ` Now we're ready to go and code the web component using TypeScript. The Map Component Implementation Let's create a src/map/map.ts file with the following content: ` The above code snippet allows the definition of a new _custom element_ through the @customElement decorator. Also, it defines the location value as a component property so that it can be configured later as: ` Also, the render method is ready to return a TemplateResult object which contains a div element that will be _rendered_ in all the available space. The element is the HTML container in which the map will be rendered later. To finish the component implementation, we'll need to write the firstUpdated method. ` Before creating the map object, it's required to initialize the communication with the back-end services provided by HERE maps. In that way, an H.service.Platform object is created using the value you got in previous steps. However, most of the code in the previous block has to do with the initialization of the map: - An instance of H.Map class is created specifying the container element, the map type to use, the geographic coordinates to be used to center the map, and a zoom level. - In case you need to make your map interactive, an H.mapevents.Behavior object can be created to enable the event system through a MapEvents instance. - On other hand, the default UI components for the map can be added using the H.ui.UI.createDefault method. - The resize listener can be used to make sure the map is rendered in the entire container. Using the Map Component As a final step, we'll need to update the spa-heremaps-lit.ts file: ` Since this class defines a new _custom element_ as a container for the map component, it's required to import the previous component definition using import './map/map'. Then, inside the class definition we can find: - The static styles attribute defines the styles for the component using a tagged template literal(css) - The render method returns the HTML content through a template literal(html). - The HTML content uses the previous custom element we created: The screenshot shows the map rendered in the main component of the application. Source Code of the Project Find the latest version of this project in this GitHub repository: spa-heremaps-lit. If you want to see the final code for this article, take a look at 01-setup-lit-heremaps tag. Do not forget to give it a star ⭐️ and play around with the code. Feel free to reach out on Twitter if you have any questions. Follow me on GitHub to see more about my work....
Aug 5, 2021
5 mins
Web Components Communication Using an Event Bus
Imagine you're building a Single Page Application using Web Components only. You have several pages, have configured the routes, and need to be able to handle general events or actions. Here's when you start to think about potential solutions as well: Maybe it's time to add state management to the application? Is it a good time to build a "custom" solution? What about using some design patterns in this case? The answers to these questions will depend on the complexity of the current scenario, the experience of the developers, or on the opinions of the team. It is clear that there is no absolute answer! In this article, we'll go over how to communicate between components using a custom Event Bus implementation. What is an Event Bus? The Event Bus idea is generally associated with the Publish-subscribe pattern: > Publish–subscribe is a messaging pattern where senders of messages, called publishers, do not program the messages to be sent directly to specific receivers, called 'subscribers', but instead, categorize published messages into classes without knowledge of subscribers In other words, an Event Bus can be considered as a global way to transport messages or events to make them accessible from any place within the application. Web Components Communication When you're working with Web Components through LitElement, it's usual firing events for sending messages between them. You can use either Standard or Custom events. * Fire a Standard Event using new Event('event') * Fire a Custom Event using new CustomEvent('event', {...options}) For a practical example, let's assume we have two components at this time: The first one could be named as a _parent component_ and the second one as the _child component_ The Child Component The child component is defined as a custom button implementation only. ` The above code snippet does the following: * It creates a model for the data to be passed through a Custom Event. The model is defined as an interface called MyButtonEvent. * Next, the component is created using a TypeScript class with the help of the LitElement decorators * The @customElement decorator allows the component definition using a name for it: my-button. It is applied at the class level. * The static styles attribute defines the styles for the component using a tagged template literal(css) * The @property decorator, which allows declaring properties in a readable way. * The render method returns the HTML content through a template literal(html). This function will be called any time label property changes. Now pay attention to the render() method. It does use the @click binding into the template. And this allows capturing the _click event_ itself in a declarative way. The Parent Component The parent component works as a _container_ since it will be in charge of the custom button rendering. Here's how the template will be using the _child_ component: ` However, in a real-world scenario, this parent component we'll need to handle the child event myClick once it gets fired. ` Find a brief explanation of the previous code snippet before starting to use the Event Bus. * The render function defines a template literal, and makes use of the my-button element using as if it were part of the HTML vocabulary * The @myClick attribute sets a function reference to handle the event in a declarative syntax. * The label attribute sets the text displayed in the button. Anytime it changes, the button will be rendered again. * The handleClick function receives an Event object with more information about it. Open your browser's console, and feel free to inspect this value. In case you require sending data along with the event, the handleClick method can be updated accordingly: ` Event Bus Communication For this example, we can assume that the parent component will act as the "root" of all events to be used through the Event Bus object. Then, let's register an alert event in the constructor method. The purpose of it will be to render an alert message from different places in the application. ` Once you _register_ an event, you can get the Registry object to be able to _unregister_ later. You're ready to go! As a next step, let's dispatch an alert event every time the button gets "clicked". This can be done within the handleClick function: ` Now the Event Bus is working as expected. You can start registering/dispatching other events from other components. They do not need to be related in any way, since the communication channel for this type of event will be the Event Bus. Unregistering from the Event Bus It's important to keep track of the different events you're registering to avoid potential memory leaks in the application. For this example, we'll enable displaying the alert message only for the first time. Other clicks over the "Show Alert" button won't take any effect or dispatch actions through the Event Bus. Let's update the parent component. ` The last line of the handleClick method ensures the _unregistering_ process from the Event Bus. Thus, other calls for the alert event will be ignored. Live Demo Wanna play around with this code? Just open the embedded Stackblitz editor: Conclusion In this article, I described two ways to communicate and pass data between components. * In case the components are related, it is clear that the best way to communicate them is through simple or custom events. * If you're planning to send events across the entire application, no matter the component or the module, then the Event Bus may work for you. In other words, it's a way to just send Events to a common channel without knowing who is going to process the message at the end. Feel free to reach out on Twitter if you have any questions. Follow me on GitHub to see more about my work. Be ready for more articles about Lit in this blog....
Jun 16, 2021
5 mins
Lit 2.0 Released: Building Fast and Lightweight Web Components
In the past months, I've been actively using Web Components to build single-page applications. It has been a great experience so far, not only because I learned a lot about the latest web standards, but also because the web applications ended up being quite fast. The Web Component development story is not something new. In fact, it has been nearly three years since LitElement was introduced as a base class to build Web Components using JavaScript with the addition of great support from TypeScript. On the other hand, lit-html had been released almost four years ago as a way to create small and fast HTML templates in JavaScript. As it was expected, these two worlds evolved favorably. Lit 2.0 was announced as a single library with a major update promising simple and fast Web Components. What's New? Lit 2.0 is coming out with a lot of great new features. Smaller The templating system of Lit 2.0 weights around 2.7 KB minified, and _gzipped_(compressed). Including the component base + reactive elements, it weights 5.8 KB. The previous image shows the bundle size for lit@2.0.0-rc.1 from the BundlePhobia tool. Better This new release also includes several template improvements and a brand new class-based API for creating directives as the below example shows. ` Also, Lit 2.0 introduces the concept of Reactive Controllers which is a powerful primitive for code reuse and composition. A _Reactive Controller_ comes with the ability to "hook" into the component's lifecycle and it has its own creation API. ` In the above code snippet, the component associated with the Reactive Controller instance is called the host component. Faster The Lit team has considered efficient rendering as one of the core values for the library since a good performance is always important when you're building for the web platform. The library authors claim that Lit 2.0 is up to 20% faster on initial rendering and up to 15% faster on updates. Also, it's good to know that Lit templates are efficient in keeping track of the UI, and only updates on re-rendering. These powerful features come along with interoperability in mind: they can work anywhere you use HTML with or without any framework. Server-Side Rendering Yes, Lit 2.0 comes with a server package for rendering Lit templates and components on the server, along with a flexible client-side "hydration". The package name is below @lit-labs/ssr since it's a pre-release software at this time. However, it's expected to support a wide range of use cases: * App rendering frameworks built on top of web components. * Framework-specific plugins for rendering custom elements such as React or Angular. * Integration with static site generators. You can be up-to-date about this server-side rendering support by following the news in this repository. Connect with Lit Lit 2.0 is not only about the cool features that are already described above, it comes along with a brand-new logo, a new website, and a welcoming community. Why Lit? The Web Components written with Lit are natively supported by browsers and they can be a perfect solution to share components across your application. Also, Lit can be a useful solution to create your set of components through the _Design System_ defined by your organization. This is even more helpful when your team uses multiple libraries and frameworks to build applications! Community You can be the first to know the good news about Lit and the upcoming releases. Share your ideas and projects with the community. * Join the conversations on Twitter: @buildWithLit * Send your issues or even better, help with Pull Requests on GitHub * Send your questions and help with technical issues on StackOverflow. Use lit, lit-html and lit-element as the related tags. * Finally, you can be part of lit-and-friends on Slack. Just always remember to be nice to each other! Playground If you are a Developer who really enjoys and thinks through interactive examples, you cannot miss the Lit Playground website, which comes with the classic "Hello World" examples (using JavaScript and TypeScript), and others covering template concepts, directives, and more. Conclusion In case you were using both LitElement and lit-html (like me), it could be a great opportunity to upgrade your code to Lit 2.0. The general idea to do this involves updating the npm packages, importing paths, updating any custom directive, and using the class-based API or even adapt to minor breaking changes. Luckily, there is a guide available for upgrades. If you're new in the world of Web Components, welcome! There is a step-by-step Lit tutorial available too. Feel free to reach out on Twitter if you have any questions. Follow me on GitHub to see more about my work. Be ready for more articles about Lit on this blog....
May 17, 2021
4 mins
How to Share Styles in Web Components with LitElement and TypeScript
Have you ever thought about the benefits of code reuse? It is common to try to find techniques or strategies that allow us to save time and reuse existing code. However, let's start by first understanding what we mean by code reuse. > Code reuse, also called software reuse, is the use of existing software, or software knowledge, to build new software, following the reusability principles. According to this definition, we may think of code blocks in different levels: development scripts, software components, testing suites, templates, styles, etc. In this article, we'll deep dive over the Web Components creation to understand how to reuse the styles through LitElement and TypeScript. A Simple Web Component Let's get started creating a basic component to describe the main parts of it. ` In the above code snippet, there is a new class CorpButton, which extends from the LitElement base-class. However, one important part here is the use of the @customElement decorator that allows us to register our brand new component in a compact definition. On other hand, the render function returns the HTML content to be _rendered_ by the component. This template is still using JavaScript notation since a template literal is being used via lit-html, and that means it can include JavaScript expressions inside. How cool is that? Also, pay attention to the styles defined, using a tagged template literal (again), and the css tag function. The styles property has been defined using the static keyword for performance reasons, and it makes sense thinking it will be applied to a class level rather than every instance of it. That's all for this initial component, and it's ready to be rendered using the following notation. ` Sharing Styles Now, let's suppose we're building another web component, and for some reason, we're going to need the same styles. Then, it's a good opportunity to apply the _code reuse_ principles. Style Inheritance Inheritance is a core concept of any Object-Oriented Programming. Since we're using TypeScript, we can take advantage of it derive a class from CorpButton as follows. ` In the above example, we do the following: * The new class extends from CorpButton(the previous class-component) instead of LitElement. This means the CorpButton class can inherit attributes and behavior from its parent class. * Instead of defining a static property styles as the parent component does, it creates a static function instead to be able to perform a call to super.styles, and get access to its parent styles. This is perfectly doable because the styles property can be a tagged template literal or even an array of them. ` Style Modules If you're more in favor of implementing composition over inheritance, there's another technique to share styles between components. The first step is to identify the styles that need to be shared. Then, you can move forward by creating a TypeScript module to contain the common styles. ` To implement this module, we created a new folder /button/styles. Then, the styles-button.ts file contains the exported styles using, again, the _tagged styles_ notation. The previous definition can be imported in your new component as follows. ` In this case, we just imported the styles module, and the styles property gets updated with an array of tagged template literals: ` This is a powerful feature since it can help us import several styles of modules as required by the new component. Please note the use of the styles as a property, and a method in the above examples. Live Demo Want to play around with this code? Just open the Stackblitz editor: Feel free to reach out on Twitter if you have any questions. Follow me on GitHub to see more about my work....
May 6, 2021
3 mins
How to Observe Property Changes with LitElement and TypeScript
In a previous post, I explained how to manage LitElement properties using @property and @internalProperty decorators through TypeScript. Also, I explained how LitElement manages the declared properties and when it triggers an update cycle, causing the component to re-render its defined template. A couple of days ago, I saw an interesting question regarding these property changes on a developer website: > How to observe @property changes in a LitElement component? In this article, I will explain how you can observe (and "react" maybe?) these properties considering the lifecycle of a LitElement component. A Practical Use Case Let's suppose you're building a small application that needs to display a list of _Users_. You can select any of them and other details should be displayed. In this case, the _Address_ information is displayed. First Steps Instead of creating a full project from scratch, we'll take the @property vs @internalProperty demo as the starting point. Open the link and create a fork to follow up with next steps. Project Content Once you complete the _fork_, you'll have a project ready with: * The Data Model, using TypeScript interfaces and static typing. * A Data Set, which exports two constants for easy testing: users and address. * Two Web Components using LitElement * The MainViewer Component, which is a _container_ component that will be in charge of displaying both the list of users and their details. * The AddressViewer Component, which is a _child_ component that receives the userId selected in the main list. Property Changes Let's take a closer look at the existing components to understand the main properties that will be considered later. The main-viewer.ts file defines the following template: ` The code snippet shows the relevance of the userId property, declared as part of the MainViewer component. Every time it changes, the render function will be triggered, sending the new property value to its child component(). On the other hand, the address-viewer.ts file defines the public property userId and determines the need of an internal property to have the Address object: ` Let's focus on the userId property of the AddressViewer component to understanding how we can observe the changes. Observing the Property Changes When a new value is set to a declared property, it triggers an update cycle that results in a re-rendering process. While all that happens, different methods are invoked and we can use some of them to know what properties have been changed. The Property's setter method This is the first place where we can observe a change. Let's update the @property() declaration in the address-viewer.ts file: ` As you can see, we just added both set and get methods to handle the brand new _userId property. Creating a new private property is a common practice when the accessor methods are used. The underscore prefix for _userId is also a code convention only. However, since we're writing our setter method here, we may need to call the requestUpdate method manually to schedule an update for the component. In other words, LitElement generates a setter method for declared properties and call the requestUpdate automatically. The requestUpdate method This method will be called when an element should be updated based on a component state or property change. It's a good place to "catch" the new value before the update() and render() functions are invoked. ` In this case, the method will receive the name of the property that has been changed along with the previous value: oldValue. Make sure to call super.requestUpdate(name, oldValue) at the end. The update method This is another option to observe the property changes. See the example below: ` The update method has a slightly different signature compared with the previous options: The changedProperties parameter is a Map structure where the keys are the names of the declared properties and the values correspond to the old values (the new values are set already and are available via this.). You can use the changedProperties.has("") to find out if your property has been changed or not. If your property has been changed, then use changedProperties.get("") to get access to the old value. A type assertion is needed here to match the static type defined by the declared property. It can be overridden to render and keep updated the DOM. In that case, you must call super.update(changedProperties) at the end to move forward with the rendering process. If you set a property inside this method, it won't trigger another update. The updated method The signature of this method will match with the update. However, this method is called when the element's DOM has been updated and rendered. Also, you don't need to call any other method since you're at the end of the lifecycle of the component. ` You can use this method to: * Identify a property change after an update * Perform post-updating tasks or any processing after updating. As a side note, if you set a property inside this method, it will trigger the _update_ process again. Live Demo Want to play around with this code? Just open the Stackblitz editor: Feel free to reach out on Twitter if you have any questions. Follow me on GitHub to see more about my work....
Mar 3, 2021
4 mins
LitElement properties: @property vs @internalProperty
LitElement is an excellent alternative to build lightweight web applications since it’s based on the Web Components standard, and with the help of TypeScript, we can see more possibilities to build web components faster with a good developer experience. In this article, I will explain the practical use of @property and @internalProperty decorators using a TypeScript implementation. The Problem Let's suppose you're building a small application that needs to display a list of _Users_. When you select any of them, other details should be displayed. In this case, it's the _Address_ information. Next, let's define the data model and a dataset before implementing the web components using LitElement. Data Modeling and Dataset The Data Model Let's rely on TypeScript _interfaces_ and static typing to have the model ready. ` As you may note, the Address interface will display a set of attributes that represents a complete address. The Source of Data To make the testing easier, let's create a dataset of entities that matches the previous model. ` The relationship between the users and address is simple: The User id matches with the position of the address array. Using LitElement Properties LitElement provides different ways to manage the properties. As the documentation says: > LitElement manages your declared properties and their corresponding attributes. This can be done using either a static properties field or using decorators. Let's take the _TypeScript-way_ using the power of decorators. We'll understand the "properties management" better in the practice through the next sections. Creating the MainViewer Container Let's create a class to contain our first component. In this case, we'll define a _container_ component that will be in charge of displaying both the list of users and their details. ` Let's explain what is happening in this component so far: * The static styles attribute defines the styles for the component using a tagged template literal (css). * It defines two class properties: users to "store" the set of Users to be displayed in the main list. Also, the userId will contain a reference of the selected User identifier (this value will be changed every time you select a different user). * The render method returns the HTML content through a template literal (html). This function will be called any time a component property changes. * The connectedCallback function makes a call to getUsers in order to get the initial data when the component is added to the document's DOM. * The getUsers function should perform an asynchronous call (in a real-world scenario) to retrieve the data. * The viewAddress function receives an id of the object selected once the user performs a _click_ action over the link. Then, the class property userId will be updated. The previous code is perfectly fine. However, it won't display any data yet! We'll only see the title and a blank section on the page and no list of users rendered. Using the @internalProperty Decorator In order to fix this rendering issue, we should make sure to _trigger_ an update cycle for the web component. Think for a while about when the update cycle should be performed: every time you change the list of users! However, this cannot be done every time you update any variable or attribute from your class. Instead, you should mention which attributes are "keys" to perform the _rendering_ operation or keep your component _updated_. We'll call LitElement properties to these key attributes. Once you have identified them, we'll need to declare these attributes as properties: ` Why use @internalProperty in this case? * For this MainViewer component, we don't need to reference either users or userId from outside the component. * From the previous point, we can consider users and userId attributes as _private_ or _protected_. In other words, LitElement observes and "reacts" to these property changes so the template gets rendered/updated automatically. Using the @property Decorator Creating the AddressViewer Component Before creating the _child_ component, let's think about how we are going to use it from the container. In terms of web components, let's suppose we'll need the following element and attribute: ` That means the new address-viewer component will need to "receive" the userId value to be able to retrieve the respective Address. The .userId=${userId} notation applies a one-way data binding to a property, meaning the AddressViewer component will have the userId as a public property. @property vs @internalProperty decorators Let's take the previous consideration into account and create a new file address-viewer.ts: ` Again, let's take a closer look at the previous source code: * The userId attribute is defined as a public property for the component using @property decorator. * The userAddress property doesn't need to be public property for the component. Instead, it's defined using @internalProperty decorator to _trigger_ the update cycle once it gets changed. * Initially, It's undefined * The render method returns the HTML content to be rendered every time a property is changed. * Note the function will return a meaningful template only once the userAddress contains the required object. * The update function reflects property values and calls the render function. * It receives a Map with the properties that have been changed. * It verifies if the userId property has been changed, and then performs a call to loadAddress. * Whenever you override this method, you'll need to call super.update() to render your template. * The loadAddress function takes the new value for userId and calls the utility function to retrieve the Address object. The brand-new AddressViewer component is ready, and we'll need to use it as a _child_ component in the main container. Let's update the render function as follows: ` Again, pay attention to the one-way data binding .userId=${this.userId} that will trigger a _rendering_ operation over the component whenever the userId gets changed. This is magic, right? Live Demo Want to play around with this code? Open the Stackblitz editor: Feel free to reach out on Twitter if you have any questions. Follow me on GitHub to see more about my work....
Feb 17, 2021
5 mins
How to Handle Events with LitElement and TypeScript
In previous posts, I covered different topics about Web Components and Single-Page Applications using LitElement and TypeScript. It's well known that LitElement has added a good support to manage _Properties_ and _Events_ to write powerful web components. In this post, we'll focus on event handling using a LitElement-based component as a use case using the TypeScript language. The Custom Component Let's start the Web Component creation using the Stackblitz editor and define the initial code for our first component: ` The previous code creates a custom button definition using the following features from LitElement: * The @customElement decorator allows the component definition using a name for it: my-button. It is applied at the class level. * The static styles attribute defines the styles for the component using a tagged template literal(css) * The @property decorator, which allows declaring properties in a readable way. * The render method returns the HTML content through a template literal(html). This function will be called any time label property changes. How to Fire Events Once the previous code gets rendered in the browser, you'll see a custom button definition as the next screenshot shows: However, this button definition doesn't have the ability to fire events yet. Let's add that support updating the render function: ` The render function does use the lit-html @click binding into the template. This will allow capturing the _click_ event. In other words, we're adding an event listener in a declarative way. Let's assume the brand new component needs to fire the click event. This can be done using the dispatchEvent function. ` Handling the Event In a real-world scenario, we'll need to handle (or listen) the new myClick event once it gets fired. Let's add a container component int the my-container.ts file and import the my-button.ts definition as follows: ` Let's explain what's happening there: * The render function defines a template literal and makes use of the my-button element using as if it were part of the HTML vocabulary * The @myClick attribute sets a function reference to handle the event in a declarative syntax. * The label attribute sets the text displayed in the button. Anytime it changes, the button will be rendered again. * The handleClick function receives an Event object with more information about it. Open your browser's console and feel free to inspect this value. How to Fire Custom Events There are times when the web component needs to send a value or an object (along with its attributes) when it fires the event. if that's the case, you can create a CustomEvent. Since we're using TypeScript, it would be great to create a model for the data to be passed through the Custom Event. Let's create it in the my-button.ts file as: ` Of course, you can create a separate file for this model. Now, let's update the handleClick function as follows: ` The Custom Event object is created for specifying the data type (MyButtonEvent) that will be fired as part of the detail. Remember the name of this interface: we'll make use of it next. Handling the Custom Event In a previous section, we've been handling the myClick event in the my-container.ts file. Let's update it to support our Custom Event. ` Pay attention to the event parameter and the type we're using to capture the event details: CustomEvent. This is helpful to capture the emitted object with the right type. Thanks, TypeScript! :-) Live Demo Wanna play around with this code? Just open the Stackblitz editor: Conclusion LitElement is an excellent alternative to build lightweight web applications since it's based on the Web Components standard, and with the help of TypScript, we can see more posibilities to build Web Components faster with a good developer experience. Feel free to reach out on Twitter if you have any questions. Follow me on GitHub to see more about my work....
Feb 10, 2021
4 mins
Introduction to LitElement
The use of powerful frameworks and libraries is very widespread nowadays. We can name Angular, React.js, Vue, Svelte, among others. It's hard to imagine building a web application without the use of any of these component-based frameworks. For these options, the components are reusable and configurable _widgets_. They are able to provide a custom behavior and styling and they're used as building blocks for the application. Can we share a component between these frameworks? The short answer is no. Every framework/library has a custom API definition to build components and they are not interoperable with each other. What is LitElement? According to the official LitElement website: > LitElement is a simple base class for creating fast, lightweight web components that work in any web page with any framework. That means we can use the OOP (Object-Oriented Programming) paradigm using JavaScript or even better: TypeScript. JavaScript vs TypeScript To create your first custom Web Component using JavaScript, you'll need to define a class that implements the appearance and functionality of it as follows: ` Now let's see how you can write your first Web Component using the power of TypeScript: ` As you may note, the use of TypeScript decorators will provide the ability to annotate the class declarations and members. In the next section, you can find more articles to learn and get started with LitElement and TypeScript. More about LitElement In the past months, I've been publishing several articles about using LitElement with TypeScript. Also, I've been using these technologies actively to build Single-page applications, and I'm happy to share these resources with you: * Getting started with LitElement and TypeScript * Routing Management with LitElement and TypeScript * Navigation Lifecycle using Vaadin Router, LitElement and TypeScript * Web Components Integration using LitElement and TypeScript * Testing Web Components with Cypress and TypeScript * Testing Web Components with Karma and TypeScript * Using Route Guards, Actions and Web Components * How to Serve a Single Page Application (SPA) using Rollup.js and Web Dev Server * How to Setup a TypeScript project using Rollup.js * How to Build a LitElement Application with Rollup.js and TypeScript More articles are coming soon! Do not miss any of them and visit the This Dot Blog to be up-to-date. Feel free to reach out on Twitter if you have any questions. Follow me on GitHub to see more about my work....
Feb 8, 2021
3 mins
Let's innovate together!
We're ready to be your trusted technical partners in your digital innovation journey.
Whether it's modernization or custom software solutions, our team of experts can guide you through best practices and how to build scalable, performant software that lasts.