Great video, it's awesome to see it all come together, and in a very approachable way. This is the kind of thing we should be teaching new devs instead of throwing them into React bootcamps. Looking forward to the rest of this series!
Web components are growing on me, these last few tutorials are a really great intro to them. Your teaching style is great! I also like that you take accessibility into consideration as well as documenting your code! Thank you for your videos, I'm seriously considering subscribing to your courses.
I think its great that a youtube channel is finally doing native web components! I love it... and love web components but I think I disagree with the shadow dom being an anti pattern and styling is way easier being encapsulated... components are mean't to be self contained so they can be used through out any project without clashes with global code. if you want global styling the you simply create a global style sheet and use custom properties ( or css variables ) Global style sheet: :root { --bg-blue: ##4187f7; } component styles: background-color: var(bg-blue); Another issue mixing light and shadow dom is CLS obviously light dom will load first loading content first and then loads in shadom dom after this causing jumping, as far as I can see its better to stick to the shadom dom or the light not to mix them.... otherwise you will have to constantly reserve space for the shadow dom Open if anyone has any other solutions? Still learning all the awesomeness of web components thanks and keep up the great work!
I think this is a symptom of thinking about Web Components as React components rather than their own, unique thing. React has poisoned the web well. gomakethings.com/html-web-components/
Oh I totally agree that react has ruined the web.... I am massive on core web vitals and have built a web app using only native web components with html CSS and vanilla js.... That scores 100 across the board... The problem I found and if you have any suggestions is that if you mix the light Dom and the shadow dom it causes CLS... So the only way was to use web components that are self contained.
CLS (Cumulative Layout Shift) measures visual stability in Core Web Vitals. It quantifies how much elements on a page move unexpectedly as it loads. High CLS means a poor user experience, as content shifting can disrupt interactions. As the light Dom loads first and then native web components it can make elements jump about as the page loads hence I went for a full shadow dom component to fix this
Great Video! From my understanding, web components it's a browser api, it's not a component application abstraction despite the name. The problem with web development in front-end today is that: either you need a heavy and difficult framework or you have to write it from scratch like the example in the video. I wrote that exacly same app in jails-js. Which is a library that's pretty much closer to "vanilla" development. It's about 63 lines of code compared with the video which has 175. The problem with vanilla style is that you have to create everything on your own... but I really believe that there's a space for libraries that can automate that with just 8kb.
I don't really know how to respond when developers seem to dislike writing code, to be honest. That aside: Jails is, frankly, a completely different mental model for building UI. The app like the one I built in this video is probably better suited to state-based UI like Jails, but so much of what ships on the web is not.
@@O_Eduardo Sorry, that was a convoluted way of saying, "state-based UI was probably a better choice for this one, but Web Components are still awesome for many use-cases."
Hello there, I just discovered your channel in twitter because of your critique of HTMX. I'm kind of a web developer that only likes to use pure (I hate the term vanilla) html+css+js for the frontend and uses PHP for the backend (because that's what they use at my workplace, I'm actually okay with it). For several years now I haven't been able to "connect" with js frameworks, partially maybe due to the fact that I haven't got the need for it. Now, at the beginning of the year, I started working on a project that made me go "okay, this is it, this has to be modern website, with no page reloads, interactive and all of that good stuff, we will have to use a framework." In the middle of that process, I became aware of HTMX, and I just fell in love with it. HTMX allowed me to build the site only using html+css+js and make it as interactive as I needed. I don't see HTMX as a framework at all, I see it as a library that makes ajax requests super easy. So, my question for you is, if you wouldn't use HTMX, then how would you build a modern webapp without a js framework that requires to retrieve data from the server? Thanks in advance!
I actually just use PHP, a Web Component, and the fetch() method for that. No library needed. gomakethings.com/a-simpler-way-to-build-dynamic-user-interactions/
I highly suggest you look at Svelte. I am EXACTLY like you, absolutely fucking hating React and company... But Svelte saved my life, I almost gave up on programming.
That was super useful, thanks! 🙏 For self-interested reasons, I'm looking forward to hearing you cover local web storage in future episodes. Thanks again 🙂
Glad to hear it! Anything in particular you'd like to learn about local storage? If it doesn't fit into the next video, I'm happy to make a separate one specifically about it.
This is great. As much as I dislike the massive boiler plate, large file sizes, complexity etc, from old Redux and React. The complaints about React gets tiring after a while. It's great to see this hands-on video showing how to get things done.
Shadow dom is not all black or white. It very much depends on the functionality of your web components. Web components scope is not limited to only wrapping forms and inputs, even if in majority of cases it is.
@@pragmasoft I've been using Web Components for several years (to build full apps ;) and I agree with "Go Make Things" that shadow DOM functionality is only required in edge cases, for the same reasons he stated. Unfortunately, most tutorials overcomplicate things by appearing to make shadow DOM mandatory.
I’m not sure how you can say the shadow dom is an anti-pattern - whatever that means. I would think the reason why most devs reach for web components, myself included, is to make our components usable on other peoples websites, the sites we have zero control over. I work for a company that does personalization and it’s critical that our components look and feel are not at all affected by the host site - and vice versa. I don’t think this is an edge case, it’s the promise web components offer.
The Shadow DOM... 1. Adds additional complexity to the Web Component authoring experience. 2. Can introduce accessibility issues. 3. Makes components much harder to style. 4. Prevents the component from taking advantage of global styles. 5. Is often a solution in search of a problem. 6. Tries to let WC's do things "the React way," but React does those things better.
I agree with GoMakeThings. I've worked on several WC projects at various companies including building component libraries and 90% of the time we've needed to deliver highly customisable components. From my experience Shadow DOM feels like an edge case. Anyway, once you have "open" components its trivial to wrap them in a closed Shadow DOM version.
The very first paragraph on the web components documentation page immediately highlights encapsulation as its primary feature. I think you’re just trying to sound controversial by calling it an anti-pattern. It’s fine if you don’t prefer to use it that way but please don’t tell your audience they are doing it wrong. Do they make things more complex? Maybe but compared to what? Not all complexity is bad. It depends on the context.
@@cb73 Nope. I've built a LOT of Web Components. The benefits of the Shadow DOM, in my experience, are grossly outweighed by its many disadvantages. Isn't it strange how Web Components have been around for years, but only really started taking off once a bunch of folks started saying, "Hey, you don't actually need the Shadow DOM"?
Love it Chris.. Great video once again. Only thing I'm wondering about, why not use a more pure this.items array as a data source, instead of going into the DOM and getting the items from there?
I didn't really plan this project out. You saw me coding it on-the-fly, thinking through it as I went. But even if I planned it, keeping the data in an array means I know have a JS object in memory that I need to keep in-sync with the DOM (and vice-versa). It's much simpler, IMO, to use the DOM as the source of truth.
Are you on a Mac? But my real question is...around time index 6:51, what are you using to search for "gmt uuid" -- is that some sort of custom search engine you wrote? Or built into Macs? How did it know what gmt was? TIA Tom
Hi Tom! I am on a Mac, and that's a shortcut I setup in Alfred (a macOS productivity app) that redirects to the search page on my site. It appends a query string to the URL, and my site takes over and does the search from there.
No, that's just how DOM manipulation works in general. It's not specific to the shadow DOM (or lack thereof). If you target elements that don't exist yet, you'll get errors.
It's better to use the connectedCallback instead of the constructor. I ran into an issue that the javascript was loaded before the dom was loaded/ready. This is because I load the javascript in the head instead of the bottom of the page. I know I know I should change that. Either way I think using the connectedCallback is still better.
"Better" isn't the word you're looking for. "Can prevent issues in certain contexts." The problem you're describing can still happen even when using connectedCallback. There are a bunch of strategies to fix it. But in your case, DOM scripts should be loaded in the footer or use async/defer or be wrapped in a DOMContentLoaded event. What you're describing would happen if you were using plain old DOM manipulation methods, too. More on all of that here: gomakethings.com/the-different-ways-to-instantiate-a-web-component/
Sorry about that! I use a white background for my videos because it has better contrast and is thus a better choice for folks with certain vision issues. I do recognize the white can be intense, though.
Can you define all your custom elements in one file and then import them into whatever file they may be used?... Or really in the context of web components, just define all logic for a "component"/custom element in its own one file?
Yes, but the the customElements.define() method doesn't return anything, so you'd probably want to wrap it in a function so that you have something to export with your ES Module. function PickAtRandom () { customElements.define(...); } export {PickAtRandom};
I ran into problems when i tried to use a vanilla WC in a Next.js. Turns out SSR apps are not to friendly to WCs. Are there any thing we can do to solve this?
@@gomakethings it is the rerendering during hydration. I heard that a new spec called declarative shadow dom could help. I wish though that NextJs would better support web components.
Frankly, I'm disappointed. This video shows how to build a web component (not even reuseable), of which there is a ton of on YT, instead of telling what its title promises - how to build a full web app, which is a lot more than building simple web component. Under a web app I expected to see a composition of components, routing, state management, client to server interaction, caching, auth, packaging, building, publishing, deployment, version updates, and so on.
@@netssrmrz Yes that was my point about the title. So we may then conclude the answer on question in title is "no" ;) ? Basically it depends on what we assume are vanilla web components. Web components without any dependencies except web components api? Without dependencies on 3rd party web components?
@@pragmasoft the definition of Web Components is quite strict, as defined by the standard. in any case, if you feel you cant build a full app without resorting to third party libraries or dependencies, then as you state, the answer for you is "no".
How do you organize the code? How do you load the data? How to handle racing condition? How do you handle state of components without shadow dom? How about you just rephrase this YT video title?
1. I addressed state directly in this video already. 2. As I mentioned IN THE VIDEO, there's a part two coming that will cover loading the data. 3. There's no race conditions to worry about in this simple app. 4. This isn't a video about organizing code. 5. How about I just leave the title as is.
Are you planning to use the shuffled array for further functionality? Currently it feels like overkill. It should suffice to just use a random index to pick an item. The `shuffle` method could be removed and the body of the `onclick` method would just become let items = this.list.querySelectorAll('li'); let item = items[Math.floor(Math.random() * items.length)]; this.result.textContent = `You picked ${item.textContent}`;
I could do that, yea. Historically, `Math.random()` has provided a less uniformly random shuffle than the Fisher-Yates algorithm. I'm not worried about the 473 extra bytes, personally.
@@gomakethings I wasn't worried about the extra bytes, at least not primarily. Sometimes 20%+ extra code might well be worthwhile if the code becomes more readable. But my impression was that the added complexity makes the code harder to read for people who will have to maintain it or, in this particular case, for your audience. And regarding Fisher-Yates: It may well be true that Fisher-Yates is better than other shuffling methods. But here no shuffling is needed. (And BTW, the shuffle method uses Math.random() as well.) Finally, please don't get me wrong if I appear to be nit-picking. I like your videos and I just wanted to help improving. (Unfortunately youtube has no versioning support...)
Historically, the Fisher-Yates shuffle produced more random results than a simple Math.random(), which tends to skew towards the middle over time. MDN used to have details about this on their site, but they're not longer there.
This line `this.form.addEventListener('submit', this)` is like magic and just like magic it just magically picks up the `handleEvent()` function defined down there? So I must be missing some knowledge
Great video, it's awesome to see it all come together, and in a very approachable way.
This is the kind of thing we should be teaching new devs instead of throwing them into React bootcamps.
Looking forward to the rest of this series!
Web components are growing on me, these last few tutorials are a really great intro to them.
Your teaching style is great!
I also like that you take accessibility into consideration as well as documenting your code!
Thank you for your videos, I'm seriously considering subscribing to your courses.
Thanks for the kind words, and glad you're enjoying the videos!
I think its great that a youtube channel is finally doing native web components! I love it... and love web components but
I think I disagree with the shadow dom being an anti pattern and styling is way easier being encapsulated... components are mean't to be self contained so they can be used through out any project without clashes with global code.
if you want global styling the you simply create a global style sheet and use custom properties ( or css variables )
Global style sheet:
:root {
--bg-blue: ##4187f7;
}
component styles:
background-color: var(bg-blue);
Another issue mixing light and shadow dom is CLS obviously light dom will load first loading content first and then loads in shadom dom after this causing jumping, as far as I can see its better to stick to the shadom dom or the light not to mix them.... otherwise you will have to constantly reserve space for the shadow dom
Open if anyone has any other solutions? Still learning all the awesomeness of web components
thanks and keep up the great work!
I think this is a symptom of thinking about Web Components as React components rather than their own, unique thing. React has poisoned the web well.
gomakethings.com/html-web-components/
Oh I totally agree that react has ruined the web.... I am massive on core web vitals and have built a web app using only native web components with html CSS and vanilla js.... That scores 100 across the board...
The problem I found and if you have any suggestions is that if you mix the light Dom and the shadow dom it causes CLS... So the only way was to use web components that are self contained.
@@BenHewart Forgive me, but what does CLS stand for?
CLS (Cumulative Layout Shift) measures visual stability in Core Web Vitals. It quantifies how much elements on a page move unexpectedly as it loads. High CLS means a poor user experience, as content shifting can disrupt interactions.
As the light Dom loads first and then native web components it can make elements jump about as the page loads hence I went for a full shadow dom component to fix this
Happy to show you if your interested no pressure 😉
Great Video!
From my understanding, web components it's a browser api, it's not a component application abstraction despite the name.
The problem with web development in front-end today is that: either you need a heavy and difficult framework or you have to write it from scratch like the example in the video.
I wrote that exacly same app in jails-js. Which is a library that's pretty much closer to "vanilla" development.
It's about 63 lines of code compared with the video which has 175. The problem with vanilla style is that you have to create everything on your own... but I really believe that there's a space for libraries that can automate that with just 8kb.
I don't really know how to respond when developers seem to dislike writing code, to be honest.
That aside: Jails is, frankly, a completely different mental model for building UI. The app like the one I built in this video is probably better suited to state-based UI like Jails, but so much of what ships on the web is not.
@@gomakethings Fair enough
@@O_Eduardo Sorry, that was a convoluted way of saying, "state-based UI was probably a better choice for this one, but Web Components are still awesome for many use-cases."
Hello there, I just discovered your channel in twitter because of your critique of HTMX. I'm kind of a web developer that only likes to use pure (I hate the term vanilla) html+css+js for the frontend and uses PHP for the backend (because that's what they use at my workplace, I'm actually okay with it). For several years now I haven't been able to "connect" with js frameworks, partially maybe due to the fact that I haven't got the need for it. Now, at the beginning of the year, I started working on a project that made me go "okay, this is it, this has to be modern website, with no page reloads, interactive and all of that good stuff, we will have to use a framework." In the middle of that process, I became aware of HTMX, and I just fell in love with it. HTMX allowed me to build the site only using html+css+js and make it as interactive as I needed. I don't see HTMX as a framework at all, I see it as a library that makes ajax requests super easy. So, my question for you is, if you wouldn't use HTMX, then how would you build a modern webapp without a js framework that requires to retrieve data from the server? Thanks in advance!
I actually just use PHP, a Web Component, and the fetch() method for that. No library needed.
gomakethings.com/a-simpler-way-to-build-dynamic-user-interactions/
@@gomakethings thanks a lot, I'm gonna try to explore and learn about this
I highly suggest you look at Svelte. I am EXACTLY like you, absolutely fucking hating React and company... But Svelte saved my life, I almost gave up on programming.
That was super useful, thanks! 🙏 For self-interested reasons, I'm looking forward to hearing you cover local web storage in future episodes. Thanks again 🙂
Glad to hear it! Anything in particular you'd like to learn about local storage? If it doesn't fit into the next video, I'm happy to make a separate one specifically about it.
This is great. As much as I dislike the massive boiler plate, large file sizes, complexity etc, from old Redux and React. The complaints about React gets tiring after a while. It's great to see this hands-on video showing how to get things done.
Man, this is brilliant! Just what I’ve been looking for! Keep up!
Delighted to hear it! Thanks!
Chris is a great programmer. Thanks for sharing
Nice video. 100% agree on shadow dom usage.
Shadow dom is not all black or white. It very much depends on the functionality of your web components. Web components scope is not limited to only wrapping forms and inputs, even if in majority of cases it is.
@@pragmasoft I've been using Web Components for several years (to build full apps ;) and I agree with "Go Make Things" that shadow DOM functionality is only required in edge cases, for the same reasons he stated. Unfortunately, most tutorials overcomplicate things by appearing to make shadow DOM mandatory.
I’m not sure how you can say the shadow dom is an anti-pattern - whatever that means. I would think the reason why most devs reach for web components, myself included, is to make our components usable on other peoples websites, the sites we have zero control over. I work for a company that does personalization and it’s critical that our components look and feel are not at all affected by the host site - and vice versa. I don’t think this is an edge case, it’s the promise web components offer.
The Shadow DOM...
1. Adds additional complexity to the Web Component authoring experience.
2. Can introduce accessibility issues.
3. Makes components much harder to style.
4. Prevents the component from taking advantage of global styles.
5. Is often a solution in search of a problem.
6. Tries to let WC's do things "the React way," but React does those things better.
I agree with GoMakeThings. I've worked on several WC projects at various companies including building component libraries and 90% of the time we've needed to deliver highly customisable components. From my experience Shadow DOM feels like an edge case. Anyway, once you have "open" components its trivial to wrap them in a closed Shadow DOM version.
The very first paragraph on the web components documentation page immediately highlights encapsulation as its primary feature. I think you’re just trying to sound controversial by calling it an anti-pattern. It’s fine if you don’t prefer to use it that way but please don’t tell your audience they are doing it wrong. Do they make things more complex? Maybe but compared to what? Not all complexity is bad. It depends on the context.
@@cb73 Nope. I've built a LOT of Web Components. The benefits of the Shadow DOM, in my experience, are grossly outweighed by its many disadvantages.
Isn't it strange how Web Components have been around for years, but only really started taking off once a bunch of folks started saying, "Hey, you don't actually need the Shadow DOM"?
I liked the accessibility bits you had going on
Thanks! It's far too often an afterthought.
Love it Chris.. Great video once again. Only thing I'm wondering about, why not use a more pure this.items array as a data source, instead of going into the DOM and getting the items from there?
I didn't really plan this project out. You saw me coding it on-the-fly, thinking through it as I went.
But even if I planned it, keeping the data in an array means I know have a JS object in memory that I need to keep in-sync with the DOM (and vice-versa). It's much simpler, IMO, to use the DOM as the source of truth.
Are you on a Mac? But my real question is...around time index 6:51, what are you using to search for "gmt uuid" -- is that some sort of custom search engine you wrote? Or built into Macs? How did it know what gmt was?
TIA
Tom
Hi Tom! I am on a Mac, and that's a shortcut I setup in Alfred (a macOS productivity app) that redirects to the search page on my site. It appends a query string to the URL, and my site takes over and does the search from there.
@@gomakethings Very cool!
Am I correct that not using shadow DOM forces you to run the script after the DOM has loaded?
No, that's just how DOM manipulation works in general. It's not specific to the shadow DOM (or lack thereof).
If you target elements that don't exist yet, you'll get errors.
It's better to use the connectedCallback instead of the constructor. I ran into an issue that the javascript was loaded before the dom was loaded/ready. This is because I load the javascript in the head instead of the bottom of the page. I know I know I should change that. Either way I think using the connectedCallback is still better.
"Better" isn't the word you're looking for. "Can prevent issues in certain contexts."
The problem you're describing can still happen even when using connectedCallback. There are a bunch of strategies to fix it.
But in your case, DOM scripts should be loaded in the footer or use async/defer or be wrapped in a DOMContentLoaded event. What you're describing would happen if you were using plain old DOM manipulation methods, too.
More on all of that here: gomakethings.com/the-different-ways-to-instantiate-a-web-component/
Thnx for the reply and extra info!
I'd love to watch this but I can't look at a white screen for 30 minutes
Sorry about that! I use a white background for my videos because it has better contrast and is thus a better choice for folks with certain vision issues. I do recognize the white can be intense, though.
😂 100%!
Love It!
Can you define all your custom elements in one file and then import them into whatever file they may be used?... Or really in the context of web components, just define all logic for a "component"/custom element in its own one file?
Yes, but the the customElements.define() method doesn't return anything, so you'd probably want to wrap it in a function so that you have something to export with your ES Module.
function PickAtRandom () {
customElements.define(...);
}
export {PickAtRandom};
I like this, good video thanks
Thanks!
I ran into problems when i tried to use a vanilla WC in a Next.js. Turns out SSR apps are not to friendly to WCs. Are there any thing we can do to solve this?
I'd need more specifics about the errors you're seeing to answer that.
@@gomakethings There are flash effects on every page loads. This is only for Nextjs apparently due to the way it handles hydration of the DOM.
@@bourge I wonder if you're seeing flashes of unstyled content, or if the Web Components are being replaced and re-rendered because of hydration.
@@gomakethings it is the rerendering during hydration. I heard that a new spec called declarative shadow dom could help. I wish though that NextJs would better support web components.
Great, thanks.
Nice!
Thanks!
what about lit framework?
I don't like it, personally: gomakethings.com/what-about-lit-for-web-components/
The answer is yes
Frankly, I'm disappointed. This video shows how to build a web component (not even reuseable), of which there is a ton of on YT, instead of telling what its title promises - how to build a full web app, which is a lot more than building simple web component. Under a web app I expected to see a composition of components, routing, state management, client to server interaction, caching, auth, packaging, building, publishing, deployment, version updates, and so on.
That’s not a YT video. That’s a whole course. 😂
I agree the video title is not accurate but most of what you want is beyond the scope of the Web Components API and are handled by other APIs.
@@netssrmrz Yes that was my point about the title. So we may then conclude the answer on question in title is "no" ;) ? Basically it depends on what we assume are vanilla web components. Web components without any dependencies except web components api? Without dependencies on 3rd party web components?
@@pragmasoft the definition of Web Components is quite strict, as defined by the standard. in any case, if you feel you cant build a full app without resorting to third party libraries or dependencies, then as you state, the answer for you is "no".
How do you organize the code? How do you load the data? How to handle racing condition? How do you handle state of components without shadow dom? How about you just rephrase this YT video title?
1. I addressed state directly in this video already.
2. As I mentioned IN THE VIDEO, there's a part two coming that will cover loading the data.
3. There's no race conditions to worry about in this simple app.
4. This isn't a video about organizing code.
5. How about I just leave the title as is.
Are you planning to use the shuffled array for further functionality? Currently it feels like overkill. It should suffice to just use a random index to pick an item. The `shuffle` method could be removed and the body of the `onclick` method would just become
let items = this.list.querySelectorAll('li');
let item = items[Math.floor(Math.random() * items.length)];
this.result.textContent = `You picked ${item.textContent}`;
I could do that, yea. Historically, `Math.random()` has provided a less uniformly random shuffle than the Fisher-Yates algorithm. I'm not worried about the 473 extra bytes, personally.
@@gomakethings I wasn't worried about the extra bytes, at least not primarily. Sometimes 20%+ extra code might well be worthwhile if the code becomes more readable. But my impression was that the added complexity makes the code harder to read for people who will have to maintain it or, in this particular case, for your audience.
And regarding Fisher-Yates: It may well be true that Fisher-Yates is better than other shuffling methods. But here no shuffling is needed. (And BTW, the shuffle method uses Math.random() as well.)
Finally, please don't get me wrong if I appear to be nit-picking. I like your videos and I just wanted to help improving. (Unfortunately youtube has no versioning support...)
@@HeribertSchuetz I took this as a kindly discussion among peers, so no worries at all! I agree about making the code harder to read.
Why shuffle the array when you can just get a random index? array[Math.floor(Math.random() * array.length)]
Historically, the Fisher-Yates shuffle produced more random results than a simple Math.random(), which tends to skew towards the middle over time.
MDN used to have details about this on their site, but they're not longer there.
This line `this.form.addEventListener('submit', this)` is like magic and just like magic it just magically picks up the `handleEvent()` function defined down there? So I must be missing some knowledge
I wrote about it and how it works here: gomakethings.com/the-handleevent-method-is-the-absolute-best-way-to-handle-events-in-web-components/