Introduction to Lit University & Elements
Howdy, everybody, and welcome to the very first lesson at Lit University: Basics. Lit University is split into two courses: Basics and Advanced.
In Basics, we're going to tackle the very fundamentals of Lit. And in Advanced, we're going to tackle a bit more difficult topics.
I'm Elliot, a software engineer on the Lit team at Google, and today's lesson is on elements. We're going to be going over what is an element, how to make them, and how to interact with them. Let's get started.
What Is an Element?
What is an element?
As a concept, an element is just the browser's most basic component model, simple as that.
But technically, Element is a class and has subclasses such as HTMLElement, which is the superclass for elements you may already be familiar with, such as div, input, and select. Another subclass of Element is SVGElement, but for this video, we're only going to be focusing on the HTML side of things.
Now, how do you actually create an element? You can't just do new HTMLInputElement because you'll get an error. Luckily, though, the browser gives us many good ways to construct one. One of the most common ways is to simply create an HTML file and navigate to it. Once loaded, the browser will then create all the elements on the page. You can also make elements with JavaScript. For example, you can document.createElement, which takes a tag name and returns an element reference. Or you can even use element.innerHTML, which insecurely writes a string into an existing element.
For more advanced cases, you can even use a framework or library like Lit or React, but under the hood, they all just use the same browser-native methods to create these elements. We'll go deeper into rendering with Lit in a future video, but for now, let's just stick to the basics.
Interacting with Attributes
Follow me to my computer. Here we are at a beautiful blank tab in Chrome. You can open one by navigating to about:blank in your URL bar. Now I'm opening Chrome DevTools with F12.
In Chrome DevTools, we can interact with the elements on our page. Three of the most common ways of interacting with elements are attributes, properties, and events. Let's take a look at attributes.
Attributes define the characteristics of an element. Let's create an element with two attributes. We'll edit the HTML to add an input with a string attribute called value, which we'll set to "hello world", and the disabled boolean attribute. You'll see that $0 gives us the currently selected element in DevTools, in this case, <input>.
Attributes, just like the value attribute, can associate a value with a string. We can call getAttribute('value') and see that it returns the string "hello world". And the disabled attribute can be detected with the hasAttribute method, which returns true.
Now let's play around with the value attribute. You can change a string attribute by using the setAttribute method. Let's set it to "hello Lit U". You can also toggle a boolean attribute with the toggleAttribute method with the new value as the second argument. Let's set disabled to false. Look, now we can edit the input. Cool.
Attributes are really useful for a lot of things. They're good for native functionality like the selected attribute on a select element's options, which, you guessed it, will automatically select an item for you. They're also very good for statically initializing, like setting the default value on an input. They're good for styling. You can select an element by its attribute by enclosing the attribute in brackets. And finally, they're good for querying in JavaScript, which will find and return a reference to the element.
Attributes allow you to declaratively define the characteristics of your elements in a nice, readable manner that everybody can understand.
Working with Properties
One place where attributes do lack though is that they only allow passing strings and booleans around. This is where properties come in. Properties allow interacting with components through JavaScript for more advanced use cases.
You now know about the value attribute on an input, which will only initialize an input, but if the user types into the input, you'll notice that the attribute does not change. You can also get the current value in JavaScript by accessing the value property. And to set the value of an input, you also just change the property with an equal sign.
Just like attributes, properties have their own excellent use cases. One good use case for properties is to pass complex values to elements. For example, if you want to show the user's webcam in a video element, you can call the getUserMedia method, which will return a JavaScript MediaStream object, a complex object. Get a reference to the video element, and then set the srcObject property on the video element to the camera stream, and then just play.
Another good use case for properties is to fetch complex properties. For example, say we give an input element a pattern that matches only numbers. Then we can get a reference to that input and request the validity property, which returns a JavaScript object which can then be used to check if the input is valid.
Finally, another great properties use case I'd like to highlight is the ability to call methods on an element. Let's take the same input from before and get a reference to it. From here, we can call the input's reportValidity method, which will natively check to see if the input is valid and pop up an error if it's not.
Properties are a powerful way to interact with your elements in a more complex manner than attributes.
Listening for and Dispatching Events
Attributes and properties allow you to interact with elements, but they don't tell you when to interact or when something has happened. This is where events come in.
Here I am at the lit.dev playground. A link to this code should be in the description of this video. So in this example, we have an input element and a place to display our output. In the script, we have references to both elements and a function that will update the output to the input's value.
So let's say we want to print out every time the user has entered text into the input. To do this, we need to add an event listener. So let's get the input element and then add the event listener, and then pass it the event name input, and then the function that you want to be called every time the event is fired. Ta-da, we have a mirror!
Not only can you listen for events, but you can also emit your own. Let's take a quick look at this little page here. You'll see that we have a clock and an output. Then in the script, we get the references to each of those elements. Then we have an event listener on the clock element that listens for the tick event. Then we append the text "tick" to the output element. Next, you'll see setInterval. setInterval just calls the function inside of it every, in this case, one second, in which we just set the clock element's text to the current time.
But if you look at the output, you'll see that the tick event listener is not being called. Uh oh. Well, this is because the tick event is never being fired. So after every time we update the clock, let's create a new event. So const tickEvent = new Event('tick');. Then to fire the event, we need to tell it from which element to fire from. We can do that with clockEl.dispatchEvent(tickEvent). Ta-da! Now you can see that the event on the clock element is being fired.
Recap and What's Next
You can also define your own elements with something called custom elements. This is one of the foundations that Lit is built on, and we'll go over custom elements in a later video.
So to recap, elements are the basic building block of the web, but they have quite a few fundamental yet powerful ways to interact with them.
So that rounds out elements. If you have any questions, tweet us at the hashtag #asklitdev. Also, join our Lit and Friends Slack, where there are thousands of fantastic people chatting about Lit and web components.
Class dismissed.
Outro
class dismissed [Music] [Applause] [Music] you