{"id":166,"date":"2023-12-08T08:42:00","date_gmt":"2023-12-08T08:42:00","guid":{"rendered":"http:\/\/fem.flywheelsites.com\/?p=166"},"modified":"2023-12-11T16:51:11","modified_gmt":"2023-12-11T16:51:11","slug":"light-dom-only","status":"publish","type":"post","link":"https:\/\/frontendmasters.com\/blog\/light-dom-only\/","title":{"rendered":"Light-DOM-Only Web Components are Sweet"},"content":{"rendered":"\n

First: the Light DOM is just… the regular DOM. <\/p>\n\n\n\n

When people talk about native Web Components, the Shadow DOM comes up a lot. I have extremely mixed feelings about the Shadow DOM. On one hand, it’s a powerful scoping tool. For example, CSS applied inside the Shadow DOM doesn’t “leak” outside, meaning you can be freer with naming and not worry about selector conflicts. Also, JavaScript from the outside can’t reach in, meaning a querySelectorAll<\/code> isn’t going to select things inside the Shadow DOM. It’s a protective barrier that is unique to Web Components. No library can offer this, and that’s cool.<\/p>\n\n\n\n

That’s what the Shadow DOM is.<\/em> What it isn’t<\/em> is required for “HTML abstraction”, which I feel like it gets confused for. It had me confused for a while, anyway. If one of your goals for a Web Component is to hide away the HTML implementation details of a component, perhaps for ease-of-use, well, that’s great, but you can do that with the Shadow DOM or<\/em> the Light DOM.<\/p>\n\n\n\n

Let’s get into this.<\/p>\n\n\n\n

The Guts of a Custom Element Can Become Light DOM<\/h2>\n\n\n\n

Here’s a custom element defined as alert-machine<\/code>:<\/p>\n\n\n

<alert-machine<\/span>><\/span>\n  <button<\/span>><\/span>I'm a button.<\/button<\/span>><\/span>\n<\/alert-machine<\/span>><\/span><\/code><\/span>Code language:<\/span> HTML, XML<\/span> (<\/span>xml<\/span>)<\/span><\/small><\/pre>\n\n\n

In order for that to do anything, we need to execute some JavaScript that defines that element and its functionality:<\/p>\n\n\n

class<\/span> AlertMachine<\/span> extends<\/span> HTMLElement<\/span> <\/span>{\n  connectedCallback() {\n    this<\/span>.querySelector(\"button\"<\/span>).addEventListener(\"click\"<\/span>, () => {\n      alert(\"Alert machine strikes again.\"<\/span>);\n    });\n  }\n}\n\ncustomElements.define(\"alert-machine\"<\/span>, AlertMachine);<\/code><\/span>Code language:<\/span> JavaScript<\/span> (<\/span>javascript<\/span>)<\/span><\/small><\/pre>\n\n\n

I kinda prefer the slightly more elaborate setup with a constructor that allows for methods and such:<\/p>\n\n\n

class<\/span> AlertMachine<\/span> extends<\/span> HTMLElement<\/span> <\/span>{\n  constructor<\/span>() {\n    super<\/span>();\n  }\n\n  connectedCallback() {\n    this<\/span>.querySelector(\"button\"<\/span>).addEventListener(\"click\"<\/span>, this<\/span>.doAlert);\n  }\n\n  doAlert() {\n    alert(\"Alert machine strikes again.\"<\/span>);\n  }\n}\n\ncustomElements.define(\"alert-machine\"<\/span>, AlertMachine);<\/code><\/span>Code language:<\/span> JavaScript<\/span> (<\/span>javascript<\/span>)<\/span><\/small><\/pre>\n\n\n

Even if this is the first time you’re ever seeing Web Components code like this, you can make sense of it. <\/p>\n\n\n\n

What I like about what is happening so far is that <button><\/code> in the HTML is going to render on the page just like… a… <button><\/code> in HTML. It’s 100% just like that:<\/p>\n\n\n\n

    \n
  1. It renders like a <button><\/code><\/li>\n\n\n\n
  2. You can select it and style it from regular CSS with button { }<\/code><\/li>\n\n\n\n
  3. You can querySelector<\/code> it from regular JavaScript<\/li>\n<\/ol>\n\n\n\n

    It’s no different than any other HTML on the page. <\/p>\n\n\n\n

    But notice the JavaScript inside<\/em> the Web Component is adding a little extra functionality. That’s it. Neat.<\/p>\n\n\n\n