<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Cory LaViska</title>
    <description>The latest articles on DEV Community by Cory LaViska (@claviska).</description>
    <link>https://dev.to/claviska</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F208203%2F56e0cc13-5862-4dd2-85e9-81cbf0877abb.jpg</url>
      <title>DEV Community: Cory LaViska</title>
      <link>https://dev.to/claviska</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/claviska"/>
    <language>en</language>
    <item>
      <title>Web Components Are Not the Future — They’re the Present</title>
      <dc:creator>Cory LaViska</dc:creator>
      <pubDate>Fri, 27 Sep 2024 17:45:47 +0000</pubDate>
      <link>https://dev.to/claviska/web-components-are-not-the-future-theyre-the-present-347m</link>
      <guid>https://dev.to/claviska/web-components-are-not-the-future-theyre-the-present-347m</guid>
      <description>&lt;p&gt;It’s disappointing that some of the most outspoken individuals against Web Components are framework maintainers. These individuals are, after all, in some of the best positions to provide valuable feedback. They have a lot of great ideas!&lt;/p&gt;

&lt;p&gt;Alas, there’s little incentive for them because standards evolve independently and don’t necessarily align with framework opinions. How could they? Opinions are one of the things that make frameworks unique.&lt;/p&gt;

&lt;p&gt;And therein lies the problem. If you’re convinced that &lt;em&gt;your&lt;/em&gt; way is the best and only way, it’s natural to feel disenchanted when a decision is made that you don’t fully agree with.&lt;/p&gt;

&lt;p&gt;This is my open response to &lt;a href="https://dev.to/ryansolid/web-components-are-not-the-future-48bh"&gt;Ryan Carniato’s post from yesterday&lt;/a&gt; called “Web Components Are Not the Future.”&lt;/p&gt;




&lt;h2&gt;
  
  
  WTF is a component anyway?
&lt;/h2&gt;

&lt;p&gt;The word &lt;em&gt;component&lt;/em&gt; is a loaded term, but I like to think of it in relation to interoperability. If I write a component in Framework A, I would like to be able to use it in Framework B, C, and D without having to rewrite it or include its entire framework.&lt;/p&gt;

&lt;p&gt;I don’t think many will disagree with that objective.&lt;/p&gt;

&lt;p&gt;We’re not there yet, but the road has been paved and instead of learning to drive on it, frameworks are building…different roads.&lt;/p&gt;

&lt;p&gt;Ryan states:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If the sheer number of JavaScript frameworks is any indicator we are nowhere near reaching a consensus on how one should author components on the web. And even if we were a bit closer today we were nowhere near there a decade ago.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The thing is, we don’t need to agree on &lt;em&gt;how&lt;/em&gt; to write components, we just need to agree on the underlying implementation, then you can use classes, hooks, or whatever flavor you want to create them.&lt;/p&gt;

&lt;p&gt;Turns out, we have a very well-known, ubiquitous technology that we’ve chosen to do this with: HTML.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;But it also can have a negative effect. If too many assumptions are made it becomes harder to explore alternative space because everything gravitates around the establishment. What is more established than a web standard that can never change?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If the concern is premature standardization, well, it’s a bit late for that. So let’s figure out how to get from where we are now to where we want to be. The solution isn’t to start over at the specification level, it’s to rethink how front end frameworks engage with current and emerging standards and work to improve them.&lt;/p&gt;

&lt;p&gt;Respectfully, it’s time to stop complaining, move on, and fix the things folks perceive as suboptimal.&lt;/p&gt;

&lt;h2&gt;
  
  
  The definition of component
&lt;/h2&gt;

&lt;p&gt;That said, we also need to realize that Web Components aren’t a 1:1 replacement for framework components. They’re tangentially related things, and I think a lot of confusion stems from this. We should really fix the definition of &lt;em&gt;component&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;So the fundamental problem with Web Components is that they are built on Custom Elements. Elements !== Components. More specifically, Elements are a subset of Components. One could argue that every Element could be a Component but not all Components are Elements.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To be fair, I’ve never really liked the term “Web Components” because it competes with the concept of framework components, but that’s what caught on and that's what most people are familiar with these days.&lt;/p&gt;

&lt;p&gt;Alas, there is a very important distinction here. Sure, a button and a text field can be components, but there are other types. For example, many frameworks support a concept of &lt;em&gt;renderless components&lt;/em&gt; that exist in your code, but not in the final HTML. You can’t do that with Web Components, because every custom element results in an actual DOM element. (FWIW I don’t think this is a bad thing — but I digress…)&lt;/p&gt;

&lt;p&gt;As to why Web components don’t do all the things framework components do, that’s because they’re a lower level implementation of an interoperable &lt;em&gt;element&lt;/em&gt;. They’re not trying to do everything framework components do. That’s what frameworks are for.&lt;/p&gt;

&lt;h2&gt;
  
  
  It’s ok to be shiny
&lt;/h2&gt;

&lt;p&gt;In fact, this is where frameworks excel. They let you go above and beyond what the platform can do on its own. I fully support this trial-and-error way of doing things.&lt;/p&gt;

&lt;p&gt;After all, it’s fun to explore new ideas and live on the bleeding edge. We got a lot of cool stuff from doing that. We got &lt;code&gt;document.querySelector()&lt;/code&gt; from jQuery. CSS Custom Properties were inspired by Sass. Tagged template literals were inspired by JSX. Soon we’re getting &lt;a href="https://github.com/tc39/proposal-signals" rel="noopener noreferrer"&gt;signals&lt;/a&gt; from Preact.&lt;/p&gt;

&lt;p&gt;And from all the component-based frameworks that came before them, we got &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_componentsa" rel="noopener noreferrer"&gt;Web Components&lt;/a&gt;: custom HTML elements that can be authored in many different ways (because we know people like choices) and are fully interoperable (if frameworks and metaframeworks would continue to move towards the standard instead of protecting their own).&lt;/p&gt;

&lt;p&gt;Frameworks are a testbed for new ideas that may or may not work out. We all need to be OK with that. Even framework authors. &lt;em&gt;Especially framework authors.&lt;/em&gt; More importantly, we all need to stop being salty when  &lt;em&gt;our way&lt;/em&gt; isn’t what makes it into the browser.&lt;/p&gt;

&lt;p&gt;There will always be a better way to do something, but none of us have the foresight to know what a perfect solution looks like &lt;em&gt;right now&lt;/em&gt;. Hindsight is 20/20. As humans, we’re constantly striving to make things better. We’re really good at it, by the way. But we must have the discipline to reach various checkpoints to pause, reflect, and gather feedback before continuing.&lt;/p&gt;

&lt;p&gt;Even the cheapest cars on the road today will outperform the &lt;a href="https://en.wikipedia.org/wiki/Ford_Model_T" rel="noopener noreferrer"&gt;Model T&lt;/a&gt; in every way. I’m sure Ford could have made the original Model T way better if they had spent another decade working on it, but do you know what made the next version even better than 10 more years? The feedback they got from actual users who bought them, sat in them, and drove them around on actual roads.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1hof3xjwx0y0yzi74vuh.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1hof3xjwx0y0yzi74vuh.gif" alt="Baby steps? Baby steps."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Web Standards offer a promise of stability and we need to move forward to improve them together. Using one’s influence to rally users against the very platform you’ve built your success on is damaging to both the platform and the community.&lt;/p&gt;

&lt;p&gt;We need these incredible minds to be less divisive and more collaborative.&lt;/p&gt;

&lt;h2&gt;
  
  
  The right direction
&lt;/h2&gt;

&lt;p&gt;Imagine if we applied the same arguments against HTML early on. What if we never standardized it at all? Would the Web be a better place if every site required a specific browser? (Narrator: &lt;em&gt;it wasn't&lt;/em&gt;.) Would it be better if every site was Flash or a Java applet? (Remember Silverlight? lol)&lt;/p&gt;

&lt;p&gt;Sure, there are often better alternatives for every use case, but we have to pick something that works for the majority, then we can iterate on it. Web Components are a huge step in the direction of standardization and we should all be excited about that.&lt;/p&gt;

&lt;p&gt;But the Web Component implementation isn’t compatible with existing frameworks, and therein lies an existential problem.&lt;/p&gt;

&lt;p&gt;Web Components are a threat to the peaceful, proprietary way of life for frameworks that have amassed millions of users — the majority of web developers. Because opinions vary so wildly, when a new standard emerges frameworks can’t often adapt to them without breaking changes. And breaking changes can be detrimental to a user base.&lt;/p&gt;

&lt;p&gt;Have you spotted the issue? You can’t possibly champion Web Standards when you’ve built a non-standard thing that will break if you align with the emerging standard. It’s easier to oppose the threat than to adapt to it.&lt;/p&gt;

&lt;p&gt;And of course Web Components don’t do &lt;em&gt;everything&lt;/em&gt; a framework does. How can the platform possibly add all the features every framework added last week? That would be absolutely reckless.&lt;/p&gt;

&lt;p&gt;And no, the platform doesn’t move as fast as your framework and that’s sometimes painful. But it’s by design. This process is what gives us APIs that continue to work for decades.&lt;/p&gt;

&lt;p&gt;As users, we need to get over this hurdle and start thinking about how frameworks can adapt to current standards and how to evolve them as new ones emerge. Let’s identify shortcomings in the spec and work together to improve the ecosystem instead of arguing about who’s shit smells worse.&lt;/p&gt;

&lt;p&gt;Reinventing the wheel isn’t the answer. Lock-in isn’t the answer.&lt;/p&gt;

&lt;p&gt;This is why I believe that the next generation of frameworks will converge on custom elements as an interoperable component model, enhance that model by sprinkling in awesome features of their own, and focus more on flavors (class-based, functional, signals, etc.) and higher level functionality. As for today's frameworks? How they adapt will determine how relevant they remain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Living dangerously
&lt;/h2&gt;

&lt;p&gt;Ryan concludes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;So in a sense there are nothing wrong with Web Components as they are only able to be what they are. It's the promise that they are something that they aren't which is so dangerous. The way their existence warps everything around them that puts the whole web at risk. It's a price everyone has to pay.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So Web Components aren’t the specific vision you had for components. That's fine. But that's how it is.&lt;/p&gt;

&lt;p&gt;They're not Solid components. They’re not React components. They’re not Svelte components. They’re not Vue components. They’re standards-based Web Components that work in all of the above. And they could work &lt;em&gt;even better&lt;/em&gt; in all of the above if all of the above were interested in advancing the platform instead of locking users in.&lt;/p&gt;

&lt;p&gt;I’m not a conspiracy theorist, but I find interesting the number of people who are and have been sponsored and/or hired by for-profit companies whose platforms rely heavily on said frameworks. Do you think it’s in their best interest to follow Web Standards if that means making their service less relevant and less lucrative? Of course not.&lt;/p&gt;

&lt;p&gt;If you’ve built an empire on top of something, there’s absolutely zero incentive to tear it down for the betterment of humanity. That’s not how capitalism works. It’s far more profitable to lock users in and keep them paying. But you know what…?&lt;/p&gt;

&lt;p&gt;Web Standards don't give a fuck about monetization.&lt;/p&gt;

&lt;h2&gt;
  
  
  Longevity supersedes ingenuity
&lt;/h2&gt;

&lt;p&gt;The last thing I’d like to talk about is this line here.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Web Components possibly pose the biggest risk to the future of the web that I can see.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Of course, this is from the perspective of a framework author, not from the people actually shipping and maintaining software built using these frameworks. And the people actually shipping software are the majority, but that’s not prestigious so they rarely get the high follower counts.&lt;/p&gt;

&lt;p&gt;The people actually shipping software are tired of framework churn. They're tired of shit they wrote last month being outdated already. They want stability. They want to know that the stuff they build today will work tomorrow.&lt;/p&gt;

&lt;p&gt;As history has proven, no framework can promise that.&lt;/p&gt;

&lt;p&gt;You know what framework &lt;em&gt;I&lt;/em&gt; want to use? I want a framework that aligns with the platform, not one that replaces it. I want a framework that values incremental innovation over user lock-in. I want a framework that says it's OK to break things if it means making the Web a better place for everyone. Yes, that comes at a cost, but almost every good investment does, and I would argue that cost will be less expensive than learning a new framework and rebuilding buttons for the umpteenth time.&lt;/p&gt;

&lt;p&gt;The Web platform may not be perfect, but it continuously gets better. I don’t think frameworks are bad but, as a community, we need to recognize that a fundamental piece of the platform has changed and it's time to embrace the interoperable component model that Web Component APIs have given us…even if that means breaking things to get there.&lt;/p&gt;

&lt;p&gt;The component war is over.&lt;/p&gt;

</description>
      <category>webcomponents</category>
      <category>javascript</category>
      <category>frontend</category>
    </item>
    <item>
      <title>How to File a Bug Report</title>
      <dc:creator>Cory LaViska</dc:creator>
      <pubDate>Tue, 21 Nov 2023 16:15:30 +0000</pubDate>
      <link>https://dev.to/claviska/how-to-file-a-bug-report-128a</link>
      <guid>https://dev.to/claviska/how-to-file-a-bug-report-128a</guid>
      <description>&lt;p&gt;They say there's no such thing as bug-free code. When problems arise, creating a &lt;a href="https://en.wikipedia.org/wiki/Minimal_reproducible_example" rel="noopener noreferrer"&gt;minimal reproduction&lt;/a&gt; will give you the best chance of a speedy resolution.&lt;/p&gt;

&lt;p&gt;When a potential bug is discovered, many developers' first reaction is to file an issue. That's great, but please exercise due diligence before posting! Have you reviewed the docs to confirm the behavior in question? Are you able to reproduce the bug &lt;em&gt;outside&lt;/em&gt; of your app? Have you removed all unrelated code to make sure nothing else is causing the problem?&lt;/p&gt;

&lt;p&gt;I get it — creating a reproduction takes time! Why should that be on you if the bug is upstream? The thing is, the process of creating a minimal reproduction will often uncover the problem and, in many cases, the problem will be in your own code. I know that sounds arrogant but, as an open source maintainer, I see it happen quite frequently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Help Us Help You
&lt;/h2&gt;

&lt;p&gt;That's not to say our libraries don't have bugs…they totally do! We're just asking you to help diagnose the problem before we spend hours diving into &lt;em&gt;your code&lt;/em&gt; only to realize it's not something we can fix in &lt;em&gt;our code&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;If you're using our software, we've already provided some kind of value to you. It's not fair to ask us to troubleshoot your app. Maintainers generally &lt;em&gt;want&lt;/em&gt; to eliminate bugs from their software, but triaging issues can be a painstaking task, especially in larger projects.&lt;/p&gt;

&lt;p&gt;Even if your bug report is completely valid, an issue that lacks sufficient information — or has too much of the &lt;em&gt;wrong&lt;/em&gt; information — can easily fly under the radar for many reasons.&lt;/p&gt;

&lt;p&gt;Think of it from a maintainer's perspective. You wake up in the morning to three new bug reports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bug #1&lt;/strong&gt; – doesn't have enough information, just a screenshot of the suspected problem and a line of text that vaguely describes it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bug #2&lt;/strong&gt; – has multiple screenshots of CI output and VS Code windows, but nothing else.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bug #3&lt;/strong&gt; – has a clear description of the problem and a minimal reproduction. The submitter has thoughtfully included all relevant information pertaining to the issue.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which one would &lt;em&gt;you&lt;/em&gt; be most willing to resolve first?&lt;/p&gt;

&lt;h2&gt;
  
  
  Better Bug Reports
&lt;/h2&gt;

&lt;p&gt;Here are some tips to help you get results faster. Investing a bit of time up front will usually lead to a more positive result. After all, there's nothing worse than watching your issue collect dust.*&lt;/p&gt;

&lt;h3&gt;
  
  
  Do
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Be courteous and responsive&lt;/li&gt;
&lt;li&gt;Search for existing issues&lt;/li&gt;
&lt;li&gt;Provide all the information necessary to reproduce the problem&lt;/li&gt;
&lt;li&gt;Provide a minimal reproduction when it makes sense&lt;/li&gt;
&lt;li&gt;Taper your expectations — many maintainers do this for free!&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Don't
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Include information that doesn't pertain to the bug&lt;/li&gt;
&lt;li&gt;Include multiple bug reports in the same issue&lt;/li&gt;
&lt;li&gt;Be rude to maintainers or anyone else involved&lt;/li&gt;
&lt;li&gt;Spam the maintainers with follow ups&lt;/li&gt;
&lt;li&gt;Point fingers or blame others — it's just not productive&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Just for Fun
&lt;/h2&gt;

&lt;p&gt;In case you were wondering, here's how maintainers tend to feel when various bug reports are filed. 🤣&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkm0n75sqhuxc60h12jzk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkm0n75sqhuxc60h12jzk.png" alt="Bug Reports" width="800" height="969"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;small&gt;&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;*Unfortunately, some maintainers &lt;em&gt;are&lt;/em&gt; simply unresponsive. In my experience, the majority of open source authors care about their projects and want to be good stewards. Sometimes it can help to offer a bounty or, better yet, a PR. Alas, I've seen really good PRs collect dust too. In that case, you might need to consider forking the project or finding an alternative.&lt;/p&gt;



</description>
    </item>
    <item>
      <title>Custom Event Names and the Bubbling Problem</title>
      <dc:creator>Cory LaViska</dc:creator>
      <pubDate>Mon, 12 Dec 2022 22:07:18 +0000</pubDate>
      <link>https://dev.to/claviska/custom-event-names-and-the-bubbling-problem-d3</link>
      <guid>https://dev.to/claviska/custom-event-names-and-the-bubbling-problem-d3</guid>
      <description>&lt;p&gt;The topic of custom element event names comes up every now and then, especially from &lt;a href="https://shoelace.style/" rel="noopener noreferrer"&gt;Shoelace&lt;/a&gt; users who get confused when events of the same name are emitted from different components.&lt;/p&gt;

&lt;p&gt;Take &lt;a href="https://shoelace.style/components/details" rel="noopener noreferrer"&gt;&lt;code&gt;&amp;lt;sl-details&amp;gt;&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://shoelace.style/components/dialog" rel="noopener noreferrer"&gt;&lt;code&gt;&amp;lt;sl-dialog&amp;gt;&lt;/code&gt;&lt;/a&gt;, and &lt;a href="https://shoelace.style/components/dropdown" rel="noopener noreferrer"&gt;&lt;code&gt;&amp;lt;sl-dropdown&amp;gt;&lt;/code&gt;&lt;/a&gt;, for example. They all emit &lt;code&gt;sl-show&lt;/code&gt; and &lt;code&gt;sl-hide&lt;/code&gt; events, allowing you to hook into their lifecycle as they open and close. Occasionally, someone will nest a component inside another, listen for an event such as &lt;code&gt;sl-hide&lt;/code&gt;, and wonder why the callback executes at the "wrong time."&lt;/p&gt;

&lt;p&gt;In this example, you can see that we have an &lt;code&gt;&amp;lt;sl-dropdown&amp;gt;&lt;/code&gt; inside of an &lt;code&gt;&amp;lt;sl-dialog&amp;gt;&lt;/code&gt;. Both of these components emit &lt;code&gt;sl-show&lt;/code&gt; and &lt;code&gt;sl-hide&lt;/code&gt; events.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;sl-dialog&lt;/span&gt; &lt;span class="na"&gt;label=&lt;/span&gt;&lt;span class="s"&gt;"Dialog"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- Note how the dropdown is nested inside the dialog --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;sl-dropdown&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;sl-button&lt;/span&gt; &lt;span class="na"&gt;slot=&lt;/span&gt;&lt;span class="s"&gt;"trigger"&lt;/span&gt; &lt;span class="na"&gt;caret&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Open and close me&lt;span class="nt"&gt;&amp;lt;/sl-button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;sl-menu&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;sl-menu-item&amp;gt;&lt;/span&gt;Option 1&lt;span class="nt"&gt;&amp;lt;/sl-menu-item&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;sl-menu-item&amp;gt;&lt;/span&gt;Option 2&lt;span class="nt"&gt;&amp;lt;/sl-menu-item&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;sl-menu-item&amp;gt;&lt;/span&gt;Option 3&lt;span class="nt"&gt;&amp;lt;/sl-menu-item&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/sl-menu&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/sl-dropdown&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/sl-dialog&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;sl-button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"open"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Open Dialog&lt;span class="nt"&gt;&amp;lt;/sl-button&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dialog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sl-dialog&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;openButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;open&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Show the dialog when the button is clicked&lt;/span&gt;
  &lt;span class="nx"&gt;openButton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;dialog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;show&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

  &lt;span class="c1"&gt;// Listen for the sl-show event&lt;/span&gt;
  &lt;span class="nx"&gt;dialog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sl-show&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The dialog has opened…or has it?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Listen for the sl-hide event&lt;/span&gt;
  &lt;span class="nx"&gt;dialog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sl-hide&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The dialog has closed…or has it?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://codepen.io/claviska/pen/vYrwjyP" rel="noopener noreferrer"&gt;Try it on CodePen&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The logic above is faulty because it runs when the dialog &lt;em&gt;or&lt;/em&gt; any of the dialog's children emit the &lt;code&gt;sl-show&lt;/code&gt; or &lt;code&gt;sl-hide&lt;/code&gt; event. This occurs due to &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#event_bubbling" rel="noopener noreferrer"&gt;event bubbling&lt;/a&gt;, which is an incredibly useful feature of the platform. When events bubble up, listeners on ancestor elements will execute. This enables an extremely useful feature called &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#event_delegation" rel="noopener noreferrer"&gt;event delegation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Alas, this is also a source of confusion.&lt;/p&gt;

&lt;p&gt;Fortunately, there are a couple easy ways to work around it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Checking the Target
&lt;/h3&gt;

&lt;p&gt;Events are emitted with a &lt;code&gt;target&lt;/code&gt; property that you can inspect to determine which element emitted it. Thus, we can modify the handlers from the previous example to ensure the target is the same dialog we attached the listener to.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Listen for the sl-show event&lt;/span&gt;
&lt;span class="nx"&gt;dialog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sl-show&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;dialog&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The dialog has opened&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Listen for the sl-hide event&lt;/span&gt;
&lt;span class="nx"&gt;dialog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sl-hide&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;dialog&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The dialog has closed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://codepen.io/claviska/pen/VwdOxdO" rel="noopener noreferrer"&gt;Try it on CodePen&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Checking the Current Target
&lt;/h3&gt;

&lt;p&gt;Another way is to compare &lt;code&gt;Event.currentTarget&lt;/code&gt;, which effectively does the same thing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Listen for the sl-show event&lt;/span&gt;
&lt;span class="nx"&gt;dialog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sl-show&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentTarget&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The dialog has opened&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Listen for the sl-hide event&lt;/span&gt;
&lt;span class="nx"&gt;dialog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sl-hide&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentTarget&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The dialog has closed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://codepen.io/claviska/pen/eYKabQM" rel="noopener noreferrer"&gt;Try it on CodePen&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Checking the Event Phase
&lt;/h3&gt;

&lt;p&gt;Here's another way to ensure the event was emitted by the expected element. It's a bit more verbose, but it doesn't require a reference. Instead, we can inspect &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Event/eventPhase" rel="noopener noreferrer"&gt;&lt;code&gt;Event.eventPhase&lt;/code&gt;&lt;/a&gt; to determine which &lt;em&gt;phase&lt;/em&gt; the event is in. In this example, the listener is attached directly to the dialog, so we're interested in the &lt;code&gt;AT_TARGET&lt;/code&gt; phase.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Listen for the sl-show event&lt;/span&gt;
&lt;span class="nx"&gt;dialog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sl-show&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eventPhase&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AT_TARGET&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The dialog has opened&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Listen for the sl-hide event&lt;/span&gt;
&lt;span class="nx"&gt;dialog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sl-hide&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eventPhase&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AT_TARGET&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The dialog has closed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://codepen.io/claviska/pen/poKmxxQ" rel="noopener noreferrer"&gt;Try it on CodePen&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Not Use Unique Event Names?
&lt;/h2&gt;

&lt;p&gt;It has been proposed numerous times that custom elements should emit events with unique names to avoid such confusion. For example, instead of emitting &lt;code&gt;sl-show&lt;/code&gt; for multiple components, event names might named be based on their tag, e.g. &lt;code&gt;sl-dialog-show&lt;/code&gt; and &lt;code&gt;sl-dropdown-show&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I appreciate the idea, but this just isn't how events works. If you click a &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; you get a &lt;code&gt;click&lt;/code&gt; event, not a &lt;code&gt;button-click&lt;/code&gt; event. If you set focus to an &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt;, you get a &lt;code&gt;focus&lt;/code&gt; event, not an &lt;code&gt;input-focus&lt;/code&gt; event.&lt;/p&gt;

&lt;p&gt;For the sake of consistency with the platform, I consider this suggestion an anti-pattern that should be avoided in custom elements. Instead, developers must understand that many events bubble — including native ones — and they should be doing these checks any time elements are nested to avoid unexpected behaviors.&lt;/p&gt;

&lt;p&gt;This problem isn't exclusive to custom elements.&lt;/p&gt;

</description>
      <category>webcomponents</category>
      <category>javascript</category>
    </item>
    <item>
      <title>A Web Component Story</title>
      <dc:creator>Cory LaViska</dc:creator>
      <pubDate>Fri, 30 Sep 2022 12:23:01 +0000</pubDate>
      <link>https://dev.to/claviska/a-web-component-story-28hn</link>
      <guid>https://dev.to/claviska/a-web-component-story-28hn</guid>
      <description>&lt;p&gt;Gather 'round, it's story time.&lt;/p&gt;

&lt;p&gt;A number of years ago, I was hired by a company to rebuild a component library for their design system. The one they were replacing was built with AngularJS, but AngularJS was old and rickety and nobody wanted to use it anymore. Plus, many teams had moved on to other frameworks and one team even preferred doing everything with vanilla JS.&lt;/p&gt;

&lt;p&gt;But the company couldn't hire for AngularJS. There was no talent available. Devs had moved on. Nobody wanted to work with a "legacy framework."&lt;/p&gt;

&lt;p&gt;So they had to build something new to get out of that ecosystem. They talked about building a new component library in modern Angular. Or maybe React. A handful of engineers wanted Vue.&lt;/p&gt;

&lt;p&gt;But they knew that whatever framework they chose, they would be locking teams into it or forcing them to build their own components. This would mean duplicating effort and risking stylistic and behavioral deviations — an inevitable side effect of competing libraries.&lt;/p&gt;

&lt;p&gt;They also knew that they'd be doing this again in a few years if they picked any of today's popular frameworks, so they decided to give Web Components a try.&lt;/p&gt;

&lt;p&gt;So that's what we built, and that's what they still use to this day. It no longer matters if their teams want to build with React, Vue, Svelte, Solid, or whatever tomorrow brings.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nobody is forced to use a specific framework&lt;/li&gt;
&lt;li&gt;Nobody needs to reinvent UI primitives&lt;/li&gt;
&lt;li&gt;Upgrading or switching frameworks is much easier&lt;/li&gt;
&lt;li&gt;No duplicate efforts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At this point, you might be thinking "we only use React, so who cares?" And you can get away with that for awhile, especially if you're a single team or a small shop. I get it. React feels good and it's sticky. But all frameworks eventually fizzle out.&lt;/p&gt;

&lt;p&gt;Thanks to Web Components, large companies are realizing you don't need to rebuild buttons and other UI primitives every few years. Teams don't need to argue about frameworks anymore. You can have your cake and eat it too!&lt;/p&gt;

&lt;p&gt;It's already happening on a large scale at some of the largest companies in the world, but the impact isn't limited to big players — everyone can benefit from Web Components today.&lt;/p&gt;

&lt;p&gt;To be clear, I'm not suggesting you throw out your framework and go all in on Web Components...Web Components are &lt;em&gt;complementary&lt;/em&gt; to frameworks! In 2022, I strongly suggest building your design system with them. Knock out the UI primitives and patterns that all teams use and give devs the freedom to build with whatever framework(s) they want!&lt;/p&gt;

&lt;p&gt;Any org that goes all in on a single framework will eventually find themselves swimming upstream to hire talent to maintain legacy code and avoid framework rot. But you can reduce this burden (and the associated costs) by using Web Components in your design system.&lt;/p&gt;

&lt;p&gt;Remember that &lt;a href="https://www.abeautifulsite.net/posts/design-systems-arent-cheap/" rel="noopener noreferrer"&gt;design systems aren't cheap&lt;/a&gt;. It takes a lot of time to redesign and rebuild dozens of components, so why keep doing it every few years? It costs too much and it prevents you from shipping faster.&lt;/p&gt;

&lt;p&gt;Here's a quick case study from an open source UI library called &lt;a href="https://element.eleme.io/#/en-US" rel="noopener noreferrer"&gt;Element UI&lt;/a&gt;. This is a very popular Vue 2 library, but breaking changes in Vue 3 meant the library no longer worked! They had to build and maintain a &lt;a href="https://element-plus.org/en-US/" rel="noopener noreferrer"&gt;completely different version of the library&lt;/a&gt;, and now they maintain two separate versions — one for Vue 2 users and one for Vue 3 users. 🤦🏻‍♂️&lt;/p&gt;

&lt;p&gt;This is what happens when you go all in on a framework for UI primitives. Imagine having to maintain multiple versions of your component library for each framework — &lt;em&gt;and each major version&lt;/em&gt; — you want to support.&lt;/p&gt;

&lt;p&gt;Thanks to Web Components, this it totally avoidable!&lt;/p&gt;

&lt;p&gt;A common criticism I hear is that Web Components aren't perfect, to which I'll agree. No, they're not perfect. But they're pretty damn good, they're part of the standard, and we can collectively work to improve any shortcomings they might have.&lt;/p&gt;

&lt;p&gt;I'll take platform-based interoperable components over framework churn any day of the week. ✌🏻&lt;/p&gt;




&lt;p&gt;&lt;small&gt;&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;Shameless plug: you should take a look at &lt;a href="https://shoelace.style/" rel="noopener noreferrer"&gt;Shoelace&lt;/a&gt; if you're looking for an awesome library of web components.&lt;/p&gt;

&lt;p&gt;This post was originally a &lt;a href="https://twitter.com/claviska/status/1575505182175408128" rel="noopener noreferrer"&gt;Twitter thread&lt;/a&gt;.&lt;/p&gt;



</description>
      <category>webcomponents</category>
      <category>designsystems</category>
      <category>html</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Buttons and Cursors</title>
      <dc:creator>Cory LaViska</dc:creator>
      <pubDate>Wed, 27 Jul 2022 16:37:00 +0000</pubDate>
      <link>https://dev.to/claviska/buttons-and-cursors-j45</link>
      <guid>https://dev.to/claviska/buttons-and-cursors-j45</guid>
      <description>&lt;p&gt;There's a post from 2016 entitled &lt;a href="https://medium.com/simple-human/buttons-shouldnt-have-a-hand-cursor-b11e99ca374b" rel="noopener noreferrer"&gt;Buttons shouldn't have a hand cursor&lt;/a&gt; that's been making its way around social media this week. While the author is correct in his statement that operating system buttons don't have hand cursors, the pattern has become ubiquitous and somewhat expected on the Web.&lt;/p&gt;

&lt;p&gt;Some of his points include:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When a button has the hand cursor, it subtly suggests that the user is interacting with a link when they’re not.&lt;/p&gt;

&lt;p&gt;The hand cursor is reserved for links. This is because they are unique in their behaviour.&lt;/p&gt;

&lt;p&gt;Links have always been handled this way since the web came along — this is the convention of the web that you need not innovate on.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Admittedly, most of my designs as of late &lt;em&gt;do&lt;/em&gt; include &lt;code&gt;cursor: pointer&lt;/code&gt; for buttons as well as other clickable, non-link controls. And while I don't have a strong opinion either way, revisiting that post triggered a thought about the psychology behind user interfaces.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learned Behaviors
&lt;/h2&gt;

&lt;p&gt;As a computer user, you undoubtedly know what radio buttons are and how they work. But &lt;em&gt;how&lt;/em&gt; do you know that? Do you remember the very first time you used one? Probably not, but it's likely that your first experience created a pathway in your brain that said "I can only pick &lt;em&gt;one&lt;/em&gt; of these" and that knowledge has been engrained ever since.&lt;/p&gt;

&lt;p&gt;These are &lt;em&gt;learned behaviors&lt;/em&gt;. A child who has never seen a radio button before might try to click on one to make a choice. Then they might click on another one to select a second choice. Quickly, the child will realize the limitations of a radio button: "I can only pick one."&lt;/p&gt;

&lt;p&gt;That lesson remains with them until something challenges the pattern, and when such change occurs, they will dislike it because it doesn't feel correct to them. It's suddenly "unintuitive" because they've learned to expect certain behaviors, and anything unfamiliar will be called out as "poor design."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz2doaqljqlnu2tms7o3x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz2doaqljqlnu2tms7o3x.png" alt="Screenshot of a square radio and circular checkbox — wait, what?!" width="800" height="321"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is why radio buttons are almost always round and checkboxes are almost always square. Swapping something as simple as the shape of these controls will confuse users because it contradicts their learned behaviors.&lt;/p&gt;

&lt;h2&gt;
  
  
  How We Got Here
&lt;/h2&gt;

&lt;p&gt;If users develop such intrinsic expectations for consistent UIs, then how did the proliferation of hand cursors on buttons even occur? A theory I have dates back to the "Web 2.0" trend where buttons got bigger, more colorful, and eventually a lot flatter. When buttons stopped looking like buttons, designers threw in a subtle way to more easily distinguish them by changing the cursor.&lt;/p&gt;

&lt;p&gt;Plenty of users complained about flat design, but I believe the trend is directly related to why almost every button on the Web today has a "link cursor." It was a subtle enough change — an improvement, if you will — that made flatter controls more tolerable. Web designers slipped the pattern in and, while everyone was busy complaining about the lack of skeuomorphism and increasingly harder-to-identify buttons, nobody really noticed.&lt;/p&gt;

&lt;p&gt;Now that nearly every clickable thing on the web seems to have a hand cursor, I'd argue that &lt;em&gt;not&lt;/em&gt; doing it is the new anti-pattern, largely due to user expectations. The Web isn't an operating system and, despite the obvious inconsistency between operating system and Web interfaces, nobody seems to care.*&lt;/p&gt;

&lt;p&gt;In some ways, I wonder if this hurts the web. Those of us who would love to see Web-based technologies compete more with native apps could easily argue that Web apps should behave the same way to make them as indistinguishable as possible, but I seldom hear about this particular inconsistency in the wild.&lt;/p&gt;

&lt;p&gt;I wonder if anyone would even notice if we suddenly removed the hand cursor from all of our buttons. My guess is that few would, especially now that touch devices are more prominent for consumers. The handful of people who &lt;em&gt;would&lt;/em&gt; notice are those that &lt;em&gt;aren't&lt;/em&gt; browsing on iPhones and iPads, but "regular" computer users who, arguably, aren't so regular anymore.&lt;/p&gt;




&lt;p&gt;&lt;small&gt;&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;*Admittedly, I don't have a strong preference here. I rarely think about it, although the thought does cross my mind from time to time. I tend to side with my users' expectations and, given the ubiquity of hand cursors on the Web, I'll continue to change the cursor on buttons until there's a good reason to stop.&lt;/p&gt;



</description>
      <category>html</category>
      <category>css</category>
      <category>design</category>
      <category>ux</category>
    </item>
    <item>
      <title>Design Systems Aren't Cheap</title>
      <dc:creator>Cory LaViska</dc:creator>
      <pubDate>Mon, 21 Mar 2022 14:54:00 +0000</pubDate>
      <link>https://dev.to/claviska/design-systems-arent-cheap-2h64</link>
      <guid>https://dev.to/claviska/design-systems-arent-cheap-2h64</guid>
      <description>&lt;p&gt;Buttons are one of my favorite components. On the surface they seem simple, but in practice, they tend to be much more involved. In a post by Nathan Curtis entitled &lt;a href="https://medium.com/eightshapes-llc/and-you-thought-buttons-were-easy-26eb5b5c1871" rel="noopener noreferrer"&gt;And you thought buttons were easy?&lt;/a&gt;, he demonstrates how costs can quickly skyrocket to $1,000,000 when one arm of the organization isn't aware of what the other is doing.&lt;/p&gt;

&lt;p&gt;This is easy to brush off as an extreme example that only applies to really large companies. But how much does a design system actually cost?&lt;/p&gt;

&lt;h2&gt;
  
  
  A Real Life Example
&lt;/h2&gt;

&lt;p&gt;Before joining Microsoft, I did a short stint at a company with more than 10,000 employees. I was on a dedicated design system team that included five engineers, four designers, and two design technologists. Over the course of 12 months, they had built about 30 components for their design system.&lt;/p&gt;

&lt;p&gt;Many of those positions paid six figure salaries, and that doesn't account for benefits and HR costs. Let's pretend the average salary for each position was only $100K USD. That's 11 FTEs working for a year, &lt;em&gt;totaling $1.1M in salaries&lt;/em&gt;. Again, this doesn't include stock grants, health insurance, and additional benefits.&lt;/p&gt;

&lt;p&gt;All that to build buttons, dialogs, form controls, tabs — nothing proprietary. Just every day components that have been built many, many times before.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Cost of Frameworks
&lt;/h2&gt;

&lt;p&gt;I forgot to mention that the components they were building were for React, which means that only React teams can use them. As a result, either the entire company must agree to use React or non-React teams will have to duplicate effort by building the same thing in &lt;em&gt;their&lt;/em&gt; framework, running the price up even higher.&lt;/p&gt;

&lt;p&gt;In large orgs, these costs tend to fly under the radar, but they're tangible expenses if you know where to look.&lt;/p&gt;

&lt;p&gt;Many design system teams I've spoken with are rebuilding or preparing to rebuild "legacy" design systems. The story usually goes something like "we're phasing out Angular 1.x" or "we're evolving from a Bootstrap-like design system."&lt;/p&gt;

&lt;p&gt;And a lot of them want to build in React.&lt;/p&gt;

&lt;p&gt;This leads to more costs that aren't being realized. Just like jQuery dominated the front end yesterday, React dominates it today. There will be something new that dominates it tomorrow. Your design system team will continue doing the same work and incurring more and more costs to keep up with framework churn. And let's not forget the cost of updating tomorrow's legacy apps, who are consumers of your soon to be legacy design system.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Platform Outlives Frameworks
&lt;/h2&gt;

&lt;p&gt;A modern design system's component library — the foundational elements from which all your apps are built — are excellent candidates for &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components" rel="noopener noreferrer"&gt;Web Components&lt;/a&gt;: a standard technology that's built into all modern browsers. Web components are used by &lt;a href="https://arewebcomponentsathingyet.com/" rel="noopener noreferrer"&gt;some of the world's largest companies&lt;/a&gt;, including Adobe, Amazon, Apple, Ford, GM, Google, Microsoft, NASA, Salesforce, SpaceX, Visa, and many, many more.*&lt;/p&gt;

&lt;p&gt;If you care about longevity and cost, the platform is simply a more logical choice because browsers have committed to supporting Web Components for a long time.&lt;/p&gt;

&lt;p&gt;It's astonishing to me that so many engineers fail to see that doing the same work over and over again isn't productive nor cost effective. How many times do you have to rebuild a button before you think "maybe this isn't the best way forward?" Imagine how much more productive an organization could be if those design and engineering hours were spent elsewhere.&lt;/p&gt;

&lt;p&gt;Now imagine if you didn't have to build all those portable UI primitives yourself. What if you could just apply some of your own styles and start building patterns and apps? 🤔&lt;/p&gt;

&lt;h2&gt;
  
  
  Jump Starting Your Design System
&lt;/h2&gt;

&lt;p&gt;Every design system is different, but how much would you save if you could kick things off with a solid set of accessible, well-tested components? Imagine &lt;em&gt;not&lt;/em&gt; spending $1,000,000 on buttons. Imagine jumping right in and building more useful components for your organization. Imagine telling your engineers to use whatever framework they want because it will work just fine with your design system.&lt;/p&gt;

&lt;p&gt;That's one of the reasons I built &lt;a href="https://shoelace.style/" rel="noopener noreferrer"&gt;Shoelace&lt;/a&gt;, an open source web component library that serves as a design system starter kit.**&lt;/p&gt;

&lt;p&gt;Shoelace solves real world problems by offering accessible, intuitive, and interoperable components that save teams and individuals tens of thousands of dollars or more. It's totally free, by the way, although &lt;a href="https://github.com/sponsors/claviska" rel="noopener noreferrer"&gt;sponsorships are always welcome&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There's no need to roll your own buttons anymore.&lt;/p&gt;




&lt;p&gt;&lt;small&gt;&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;*There's a longstanding misconception that Web Components aren't ready for mainstream consumption. This is a stale argument that held more water many years ago when the standards were less mature. These days, companies such as Adobe are embracing Web Standards by &lt;a href="https://web.dev/ps-on-the-web/" rel="noopener noreferrer"&gt;migrating flagship products to web components&lt;/a&gt;. Web components aren't just ready for mainstream — they &lt;em&gt;are&lt;/em&gt; mainstream.&lt;/p&gt;

&lt;p&gt;**One of my followers told me they didn't want to use a third-party library as a basis for their design system. I suggested they fork the project if they want to have complete control of it. Their reply was something like, "but then I have to maintain it myself!" That argument wasn't well thought out, because you'll still be maintaining it yourself if you build it from scratch!&lt;/p&gt;



</description>
      <category>designsystems</category>
      <category>webcomponents</category>
      <category>css</category>
      <category>javascript</category>
    </item>
    <item>
      <title>CSS Parts Inspired by BEM</title>
      <dc:creator>Cory LaViska</dc:creator>
      <pubDate>Thu, 10 Mar 2022 16:48:00 +0000</pubDate>
      <link>https://dev.to/claviska/css-parts-inspired-by-bem-3meb</link>
      <guid>https://dev.to/claviska/css-parts-inspired-by-bem-3meb</guid>
      <description>&lt;p&gt;In a previous post, &lt;a href="https://www.abeautifulsite.net/posts/valid-names-for-css-parts/" rel="noopener noreferrer"&gt;I explored valid names for CSS parts&lt;/a&gt; and discovered that there are very few restrictions in what you can call them. The purpose of that deep dive was to help identify a pattern for naming parts that lets me expose states and &lt;em&gt;subparts&lt;/em&gt;, or parts exported as a result of composition.&lt;/p&gt;

&lt;p&gt;Using inspiration from &lt;a href="http://getbem.com/" rel="noopener noreferrer"&gt;BEM&lt;/a&gt;, I've settled on a familiar and intuitive pattern that I'd like to share.&lt;/p&gt;

&lt;h2&gt;
  
  
  Blocks → Parts
&lt;/h2&gt;

&lt;p&gt;In BEM terms, a &lt;em&gt;block&lt;/em&gt; "encapsulates a standalone entity that is meaningful on its own." Block names consist only of Latin letters, numbers, and dashes. This translates well to CSS parts.&lt;/p&gt;

&lt;p&gt;Consider the following custom element template. It's contrived, as its only purpose is to render an image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- shadow root --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;part=&lt;/span&gt;&lt;span class="s"&gt;"image"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we wanted to make a more descriptive name, we could have called the part &lt;code&gt;user-provided-image&lt;/code&gt; or something, as long as we stick to letters, numbers, and dashes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Elements → Subparts
&lt;/h2&gt;

&lt;p&gt;In BEM, &lt;em&gt;elements&lt;/em&gt; are "parts of a block [that] have no standalone meaning. Any element is semantically tied to its block." An example looks like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"block"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  ...
  &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"block__elem"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the two underscores separating the block from the element. You might be wondering how this ties into CSS parts. Since parts are unique to the shadow root, we don't need to namespace them to prevent collisions. Two different custom elements can have two different parts with the same name and that's totally fine.&lt;/p&gt;

&lt;p&gt;However, when a custom element is nested inside another custom element, it's often desirable to expose the nested element &lt;em&gt;and&lt;/em&gt; its parts, otherwise, consumers won't be able to target it fully with &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/::part" rel="noopener noreferrer"&gt;&lt;code&gt;::part()&lt;/code&gt;&lt;/a&gt;.* This means we need to expose the nested element with the &lt;a href="https://www.w3.org/TR/css-shadow-parts-1/#part-attr" rel="noopener noreferrer"&gt;&lt;code&gt;part&lt;/code&gt;&lt;/a&gt; attribute and its parts with the &lt;a href="https://www.w3.org/TR/css-shadow-parts-1/#exportparts-attr" rel="noopener noreferrer"&gt;&lt;code&gt;exportparts&lt;/code&gt;&lt;/a&gt; attribute.&lt;/p&gt;

&lt;p&gt;Let's evolve our example so it contains a nested a custom element called &lt;code&gt;&amp;lt;my-image&amp;gt;&lt;/code&gt;, and let's assume that &lt;code&gt;&amp;lt;my-image&amp;gt;&lt;/code&gt; has two parts called &lt;code&gt;photo&lt;/code&gt; and &lt;code&gt;caption&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- shadow root --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;my-image&lt;/span&gt;
    &lt;span class="na"&gt;part=&lt;/span&gt;&lt;span class="s"&gt;"image"&lt;/span&gt;
    &lt;span class="na"&gt;exportparts=&lt;/span&gt;&lt;span class="s"&gt;"
      photo:image__photo,
      caption:image__caption
    "&lt;/span&gt;
    &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;
    &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    ...
  &lt;span class="nt"&gt;&amp;lt;my-image&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see that I've exposed the host element for styling with &lt;code&gt;part="image"&lt;/code&gt;, which follows the "block" naming convention. Now take a look at the &lt;code&gt;exportparts&lt;/code&gt; attribute. Conveniently, we can rename subparts when we export them. This lets us avoid collisions (e.g. what if the host element and the nested element have parts of the same name?).&lt;/p&gt;

&lt;p&gt;In this example, the host element is exposed through the &lt;code&gt;image&lt;/code&gt; part, and its &lt;code&gt;photo&lt;/code&gt; and &lt;code&gt;caption&lt;/code&gt; subparts are exposed as &lt;code&gt;image__photo&lt;/code&gt; and &lt;code&gt;image__caption&lt;/code&gt;, respectively. Notice how everything is scoped to the &lt;code&gt;image&lt;/code&gt; block now?&lt;/p&gt;

&lt;p&gt;End users can now use a very familiar syntax for targeting the nested element and all its parts in their CSS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;::part&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* matches the nested &amp;lt;my-image&amp;gt; element */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;::part&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;image__photo&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* matches the subpart named photo in &amp;lt;my-image&amp;gt; */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;::part&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;image__caption&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* matches the subpart named caption in &amp;lt;my-image&amp;gt; */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's not uncommon for custom element authors to neglect to export parts. At the time of this writing, &lt;code&gt;exportparts&lt;/code&gt; seems to be one of the lesser known features of web components, but &lt;a href="https://caniuse.com/mdn-html_global_attributes_exportparts" rel="noopener noreferrer"&gt;it's well-supported&lt;/a&gt; and incredibly powerful.&lt;/p&gt;

&lt;p&gt;Anyways, this is feeling pretty good so far!&lt;/p&gt;

&lt;h2&gt;
  
  
  Modifiers → States
&lt;/h2&gt;

&lt;p&gt;Element state is a pretty simple concept. If you have a button, it can have a hover state, a focus state, an active state, etc. Normally, we can target such states with CSS using pseudo selectors.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* targets the button's hover state */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This also works with parts, too.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;::part&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* targets the image part's hover state */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But not all states are available to target with pseudo selectors, and what if you want to add custom states? More often than not, custom element authors lean on host element attributes for this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;my-image&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;loaded&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* targets the host element when the image has loaded successfully */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;my-image&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;error&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* targets the host element when the image fails to load */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While this works, mapping stateful parts to attributes on the host element isn't an elegant solution. Let's see how we can improve our example using stateful parts and a BEM-like syntax. In BEM, a &lt;em&gt;modifier&lt;/em&gt; is used "to change appearance, behavior or state" and is delimited by two dashes.&lt;/p&gt;

&lt;p&gt;Fortunately, parts are designed to work a lot like classes. In fact, they use the same &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList" rel="noopener noreferrer"&gt;DOMTokenList&lt;/a&gt; API as &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/classList" rel="noopener noreferrer"&gt;&lt;code&gt;classList&lt;/code&gt;&lt;/a&gt;. This means elements can have more than one part, and part names can be reused throughout the custom element's template!&lt;/p&gt;

&lt;p&gt;Evolving our example further, we can add modifier parts to indicate various states. Let's imagine the image in our example has loaded successfully. We can indicate this by adding the &lt;code&gt;image--loaded&lt;/code&gt; part.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- shadow root --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;my-image&lt;/span&gt;
    &lt;span class="na"&gt;part=&lt;/span&gt;&lt;span class="s"&gt;"image image--loaded"&lt;/span&gt;
    &lt;span class="na"&gt;exportparts=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;
    &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;
    &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    ...
  &lt;span class="nt"&gt;&amp;lt;my-image&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can target the loaded state using &lt;code&gt;::part()&lt;/code&gt;!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;::part&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;image--loaded&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* targets the image once it has loaded */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's no limit to the number of parts an element can have. You can add many additional states if you think they'll be useful.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- shadow root --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;my-image&lt;/span&gt;
    &lt;span class="na"&gt;part=&lt;/span&gt;&lt;span class="s"&gt;"
      image
      image--loaded
      image--square
      image--large
      image--jpeg
    "&lt;/span&gt;
    &lt;span class="na"&gt;exportparts=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;
    &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;
    &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    ...
  &lt;span class="nt"&gt;&amp;lt;my-image&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why BEM?
&lt;/h2&gt;

&lt;p&gt;While the examples herein are contrived, I'm hoping you can see the value in using the BEM convention for naming CSS parts. I chose it because it's familiar and it easily represents everything we need: parts, subparts, and states.&lt;/p&gt;

&lt;p&gt;Another big win for BEM-inspired part names is that consumers don't have to escape anything in their CSS. It's perfectly valid to name a part &lt;code&gt;image:loaded&lt;/code&gt;, for example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;part=&lt;/span&gt;&lt;span class="s"&gt;"image image:loaded"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But your users will need to escape the colon in their stylesheet, otherwise the selector won't match.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;::part&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nd"&gt;:loaded&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* this works, but requires a backslash before the colon */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This may not seem like a big deal but, in the world of CSS, escaping isn't something users typically do and they're probably going to forget. Imagine how frustrating it will be for a user to see a part called &lt;code&gt;image:loaded&lt;/code&gt; in your documentation and, when they try to implement it, it doesn't work and they don't know why.&lt;/p&gt;

&lt;p&gt;Since dashes and underscores don't need to be escaped, they're a more foolproof choice for naming parts.&lt;/p&gt;




&lt;p&gt;&lt;small&gt;&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;*The &lt;code&gt;::part()&lt;/code&gt; selector is &lt;a href="https://www.w3.org/TR/css-shadow-parts-1/#selectordef-part" rel="noopener noreferrer"&gt;intentionally limited&lt;/a&gt; by the spec so you can only target elements the custom element author explicitly exposes.&lt;/p&gt;

</description>
      <category>webcomponents</category>
      <category>javascript</category>
      <category>css</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Valid Names for CSS Parts</title>
      <dc:creator>Cory LaViska</dc:creator>
      <pubDate>Sun, 20 Feb 2022 20:46:00 +0000</pubDate>
      <link>https://dev.to/claviska/valid-names-for-css-parts-5h7l</link>
      <guid>https://dev.to/claviska/valid-names-for-css-parts-5h7l</guid>
      <description>&lt;p&gt;&lt;a href="https://www.w3.org/TR/css-shadow-parts-1/" rel="noopener noreferrer"&gt;CSS Shadow Parts&lt;/a&gt;, colloquially known as &lt;em&gt;CSS Parts&lt;/em&gt;, are used to expose elements inside a web component's shadow root so they can be styled by consumers with CSS. But what are we allowed to call these parts? What characters comprise a valid CSS part name? To find out, I had to &lt;a href="https://www.w3.org/TR/css-shadow-parts-1/#element-attrdef-html-global-part" rel="noopener noreferrer"&gt;dive into the spec&lt;/a&gt;!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The part attribute is parsed as a space-separated list of tokens representing the part names of this element.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;OK, but what exactly is a "token?" It's not really clear from this page, but we get a hint if we look at the spec for the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/::part" rel="noopener noreferrer"&gt;&lt;code&gt;::part()&lt;/code&gt; pseudo selector&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;::part() = ::part( &amp;lt;ident&amp;gt; )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It expects an &lt;code&gt;&amp;lt;ident&amp;gt;&lt;/code&gt;, whatever that is. Fortunately, there's &lt;a href="https://www.w3.org/TR/css-values-4/#typedef-ident" rel="noopener noreferrer"&gt;a link to it&lt;/a&gt; that takes us to a page that defines it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;CSS identifiers, generically denoted by &lt;code&gt;&amp;lt;ident&amp;gt;&lt;/code&gt;, consist of a sequence of characters conforming to the &lt;code&gt;&amp;lt;ident-token&amp;gt;&lt;/code&gt; grammar.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Perfect! So part names must conform to the &lt;code&gt;&amp;lt;ident-token&amp;gt;&lt;/code&gt; grammar, but what's that mean? Let's follow the link to &lt;a href="https://www.w3.org/TR/css-syntax-3/#typedef-ident-token" rel="noopener noreferrer"&gt;&lt;code&gt;&amp;lt;ident-token&amp;gt;&lt;/code&gt;&lt;/a&gt; in the spec.&lt;/p&gt;

&lt;p&gt;From that page:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;ident-token&amp;gt;&lt;/code&gt; [...] have a value composed of zero or more code points. Additionally, hash tokens have a type flag set to either "id" or "unrestricted". The type flag defaults to "unrestricted" if not otherwise set.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's not, uh, super helpful. There's a link around "code points," so let's see if that makes it more clear. The link goes to &lt;a href="https://infra.spec.whatwg.org/#code-point" rel="noopener noreferrer"&gt;this page&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A code point is a Unicode code point and is represented as "U+" followed by four-to-six ASCII upper hex digits, in the range U+0000 to U+10FFFF, inclusive. A code point’s value is its underlying number.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That seems to be a pretty wide range, though. &lt;a href="https://en.wikipedia.org/wiki/Plane_(Unicode)" rel="noopener noreferrer"&gt;According to Wikipedia:&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The last code point in Unicode is the last code point in plane 16, U+10FFFF.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So does this mean we can use any Unicode character as a CSS part name? I'm no Unicode expert, so it still isn't clear.&lt;/p&gt;

&lt;h2&gt;
  
  
  Experimenting with Various Characters
&lt;/h2&gt;

&lt;p&gt;Let's experiment and see what actually works in the browser. I created a sample custom element with the following parts, then tried styling them with &lt;code&gt;::part()&lt;/code&gt; to see what actually worked.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✅ part="a"
✅ part="a-b"
✅ part="a_b"
❌ part="a,b"
❌ part="a.b"
❌ part="a$b"
❌ part="a+b"
❌ part="a@b"
❌ part="a?b"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clearly we can't use &lt;em&gt;any&lt;/em&gt; character for part names. The browser doesn't like symbols, which feels intuitive to be honest.&lt;/p&gt;

&lt;p&gt;Let's try some more characters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✅ part="á"
✅ part="ñ"
✅ part="ę"
✅ part="Ф"
✅ part="平"
✅ part="λ"
✅ part="ה"
✅ part="字"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It seems to be OK with non-punctuation. What about emojis?!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✅ part="🥕"
✅ part="🐛"
✅ part="🐓"
✅ part="💩"
✅ part="🤨"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Totally fine. So it seems like any character except punctuation is good. Let's check out that lower Unicode range the spec referred to: U+0000&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.unicode.org/charts/PDF/U0000.pdf" rel="noopener noreferrer"&gt;Here's a document&lt;/a&gt; with the lower end character points. It lists a number of the symbols we tried earlier in this range. 🥲&lt;/p&gt;

&lt;p&gt;Clearly this range doesn't reflect valid CSS part names. Maybe we overlooked something in the spec, or maybe the CSS spec defines the argument too generically. Surely &lt;a href="https://html.spec.whatwg.org/#global-attributes" rel="noopener noreferrer"&gt;the HTML spec&lt;/a&gt; will explain it better.&lt;/p&gt;

&lt;p&gt;Whoops...there's no mention of the &lt;code&gt;part&lt;/code&gt; attribute at all. 😭&lt;/p&gt;

&lt;p&gt;Let's see if &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes#attr-part" rel="noopener noreferrer"&gt;this MDN page&lt;/a&gt; can help us clear things up.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A space-separated list of the part names of the element. Part names allows CSS to select and style specific elements in a shadow tree via the ::part pseudo-element.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;OK, but &lt;em&gt;what&lt;/em&gt; is a valid part name?!&lt;/p&gt;

&lt;h2&gt;
  
  
  MDN To The Rescue
&lt;/h2&gt;

&lt;p&gt;I'm still not sure what's correct per the spec. Let's take a look at &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/::part" rel="noopener noreferrer"&gt;the &lt;code&gt;::part()&lt;/code&gt; docs&lt;/a&gt; in MDN now. I found this, which looks a lot like what we saw in the spec!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;::part( `&amp;lt;ident&amp;gt;+` )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's a link around &lt;code&gt;&amp;lt;ident&amp;gt;&lt;/code&gt; that goes &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/ident" rel="noopener noreferrer"&gt;to this page&lt;/a&gt;, which says:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3pcer0v4q85hp3g789f1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3pcer0v4q85hp3g789f1.png" alt="Screenshot from the aforementioned page that shows the definition of &amp;lt;ident&amp;gt;" width="800" height="542"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thus far, MDN has provided the most human-readable explanation of what a valid ident is, and therefore what a valid CSS part name is. Here's the rundown of valid characters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A-Z, a-z&lt;/li&gt;
&lt;li&gt;0-9&lt;/li&gt;
&lt;li&gt;hyphens&lt;/li&gt;
&lt;li&gt;underscores&lt;/li&gt;
&lt;li&gt;escaped chars&lt;/li&gt;
&lt;li&gt;unicode chars in hex format&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This explains why my punctuation examples didn't work. Here's something interesting, though:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;an escaped character (preceded by a backslash, )&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So &lt;em&gt;can&lt;/em&gt; we use any character? Let's try one of those parts with punctuation that didn't work again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;part=&lt;/span&gt;&lt;span class="s"&gt;"a.b"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's target it with CSS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;::part&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nc"&gt;.b&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works! So the spec is technically correct in that any character can be used, it just wasn't clear in that some of them need to be escaped.&lt;/p&gt;

&lt;p&gt;Check this out:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;part=&lt;/span&gt;&lt;span class="s"&gt;"a.b{c}|d"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And with CSS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;::part&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nc"&gt;.b&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;c\&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nt"&gt;d&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works too!&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Parts To Target State
&lt;/h2&gt;

&lt;p&gt;Until now, I've primary used a single part for each element I wanted to expose. However, &lt;a href="https://drafts.csswg.org/css-shadow-parts/#part" rel="noopener noreferrer"&gt;per the spec&lt;/a&gt;, parts should be used more like classes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Part names act similarly to classes: multiple elements can have the same part name, and a single element can have multiple part names.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I guess I should change the way I use parts. I used to think of them as an identifier, but thinking of them more like &lt;em&gt;classes&lt;/em&gt; as the spec suggests can help fill a gap!&lt;/p&gt;

&lt;p&gt;Now that I know underscores are valid, I may explore them as a convention for hover/focus/active states since we never got the &lt;code&gt;::state&lt;/code&gt; selector. For example, we can give parts a synthetic focus state or even "hoist" a natural focus state to another element in the component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;part=&lt;/span&gt;&lt;span class="s"&gt;"control control_focus"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this convention, perhaps we don't need a &lt;code&gt;::state&lt;/code&gt; selector after all!&lt;/p&gt;

&lt;h2&gt;
  
  
  Just Because You Can, Doesn't Mean You Should
&lt;/h2&gt;

&lt;p&gt;So there you have it. You can name CSS parts anything you want — just remember to escape special characters! Using the previous example, we can even remove all of the letters and make a part name with only symbols!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;part=&lt;/span&gt;&lt;span class="s"&gt;".{}|"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The selector gets a bit crazy, though.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;::part&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="o"&gt;|)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* 😎 */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've tested this in all modern browsers and it appears to work consistently. Of course, this isn't very practical. Out of respect for your users, I would advise against naming your CSS parts like this! 🙈&lt;/p&gt;

&lt;p&gt;I'm torn on whether or not special characters are useful here. Perhaps for an internal pattern, but I don't think I'd expose it as part of a public API. Users will definitely forget to escape those characters in their stylesheets. For my parts, I'll probably continue using a-z and dashes most of the time.&lt;/p&gt;

</description>
      <category>webcomponents</category>
      <category>css</category>
      <category>javascript</category>
    </item>
    <item>
      <title>A Web Components Primer</title>
      <dc:creator>Cory LaViska</dc:creator>
      <pubDate>Fri, 04 Feb 2022 15:51:00 +0000</pubDate>
      <link>https://dev.to/claviska/a-web-components-primer-2k44</link>
      <guid>https://dev.to/claviska/a-web-components-primer-2k44</guid>
      <description>&lt;p&gt;On the eve of February, &lt;a href="https://twitter.com/claviska/status/1488362221134565380" rel="noopener noreferrer"&gt;I was inspired to tweet about web components&lt;/a&gt;. What started as a simple thought quickly turned into a series of tweets that folks seem to find useful. I've adapted the thread and I'm posting it here for prosperity.&lt;/p&gt;




&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;Shadow DOM? Light DOM? Slots? If you've heard of these but aren't sure what they are, maybe this will clear things up!&lt;/p&gt;

&lt;p&gt;Custom elements are a feature that's baked into modern web browsers. You can build portable, reusable elements and use them in any HTML page. The collection of browser APIs that make this possible is known as &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components" rel="noopener noreferrer"&gt;web components&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Custom elements are written in JavaScript and must be registered at runtime. A custom element's tag name must start with a-z and contain at least one dash, e.g. &lt;code&gt;&amp;lt;my-button&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shadow DOM
&lt;/h2&gt;

&lt;p&gt;One of the best (and least understood) features of web components is the ability to encapsulate styles so nothing leaks in and nothing leaks out. This is done by attaching a hidden, separate DOM to the custom element.&lt;/p&gt;

&lt;p&gt;This hidden DOM is called a "shadow DOM" or "shadow root."&lt;/p&gt;

&lt;p&gt;The shadow root lets you use simple class names and ids without worrying if other elements on the page are using the same ones. (No more BEM!)&lt;/p&gt;

&lt;p&gt;You can attach styles and scripts to a shadow root, too. It's kinda like a mini webpage within a webpage…minus the &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt;. 😂&lt;/p&gt;

&lt;h2&gt;
  
  
  The Host Element
&lt;/h2&gt;

&lt;p&gt;When you attach a shadow root to a custom element, the custom element acts as the host. Thus, we call it the "host element." Within a shadow root, you can target the host element in CSS using the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:host%28%29" rel="noopener noreferrer"&gt;&lt;code&gt;:host()&lt;/code&gt;&lt;/a&gt; selector. (OK, it's technically a function.)&lt;/p&gt;

&lt;p&gt;The host element is just another HTML element, but you control its API. You control what attributes it can have, what properties it uses, and what it renders.&lt;/p&gt;

&lt;p&gt;You can even control the content that gets "slotted in."&lt;/p&gt;

&lt;h2&gt;
  
  
  Slots
&lt;/h2&gt;

&lt;p&gt;Within a shadow root, you can create placeholders called slots. Slots let you control where child elements will be rendered in the template. The default slot looks like this in the custom element's template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;slot&amp;gt;&amp;lt;/slot&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Additional slots can be added, but must be named. In the template, that looks like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;slot&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"header"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/slot&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Given the following custom element, the default slot will be populated with the paragraph and the &lt;code&gt;header&lt;/code&gt; slot will be populated with the &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;my-element&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;slot=&lt;/span&gt;&lt;span class="s"&gt;"header"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Named Slot Example&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Lorem ipsum&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/my-element&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything you see here above is rendered in what we call the "light DOM."&lt;/p&gt;

&lt;h2&gt;
  
  
  Light DOM
&lt;/h2&gt;

&lt;p&gt;You can style things in the light DOM as you'd expect using simple CSS selectors. What you don't see is the internal HTML structure of the custom element. That stuff exists in the shadow DOM and &lt;em&gt;isn't&lt;/em&gt; exposed for styling. This is what seems to confuse and frustrate people.&lt;/p&gt;

&lt;p&gt;By default, you can't style anything other than a few inherited font properties. That doesn't sound useful at first, but the browser gives us ways to "poke through" the shadow root and apply styles.&lt;/p&gt;

&lt;p&gt;That's right. As a custom element author, you can tell users what they can and can't change in the shadow root — and enforce it!&lt;/p&gt;

&lt;p&gt;There are two primary tools we lean on for styling custom elements.&lt;/p&gt;

&lt;h2&gt;
  
  
  CSS Custom Properties
&lt;/h2&gt;

&lt;p&gt;Unlike regular CSS properties, &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties" rel="noopener noreferrer"&gt;CSS Custom Properties&lt;/a&gt;, or "CSS variables," cascade through shadow roots. They look kinda funny because they always start with two dashes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--brand-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tip: the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:root" rel="noopener noreferrer"&gt;&lt;code&gt;:root&lt;/code&gt;&lt;/a&gt; selector above targets the &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; element.&lt;/p&gt;

&lt;p&gt;To reference a CSS variable in a stylesheet, we use the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/var()" rel="noopener noreferrer"&gt;&lt;code&gt;var()&lt;/code&gt;&lt;/a&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:host&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--brand-color&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;CSS variables get interpolated, so the above will be interpreted by the browser as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:host&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But unlike Sass, nothing gets compiled! Thus, if the variable changes at runtime, the browser happily updates everything using it. Did I mention that CSS variables cascade? You can redefine CSS variables in any selector, including pseudos such as &lt;code&gt;:hover&lt;/code&gt; and &lt;code&gt;:focus&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Of course, since we can't tap into the shadow DOM to style things, the custom element will need to "expose" which CSS variables it accepts as part of its API. This is a bummer, because the custom element author will need to expose a CSS variable for every property and state you might want to target.&lt;/p&gt;

&lt;p&gt;If only we could style specific &lt;em&gt;parts&lt;/em&gt; inside the shadow DOM. 🤔&lt;/p&gt;

&lt;h2&gt;
  
  
  CSS Parts
&lt;/h2&gt;

&lt;p&gt;Well, we can! A custom element can expose "parts" which are aptly called &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes" rel="noopener noreferrer"&gt;CSS Parts&lt;/a&gt;. Parts are also defined in the custom element's template, this time through the &lt;code&gt;part&lt;/code&gt; attribute.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;part=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  ...
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This exposes a part in the shadow root called &lt;code&gt;container&lt;/code&gt; that consumers can target with CSS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;my-element&lt;/span&gt;&lt;span class="nd"&gt;::part&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;container&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can style any property you want on that part, including states such as &lt;code&gt;:hover&lt;/code&gt; and &lt;code&gt;:focus&lt;/code&gt;!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;my-element&lt;/span&gt;&lt;span class="nd"&gt;::part&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;container&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* ... */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;my-element&lt;/span&gt;&lt;span class="nd"&gt;::part&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;container&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nd"&gt;:focus&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* ... */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To recap: a CSS variable allows users to customize a single property and a CSS part allows them to customize &lt;em&gt;all properties&lt;/em&gt; on the exposed part. When authoring custom elements, it's not always clear which one to use and when. The rule of thumb I follow is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When a single value gets reused throughout a component's styles, a CSS custom property is usually fine&lt;/li&gt;
&lt;li&gt;When you need to expose more than a handful of properties on a single element, a CSS part is usually better&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  "Why can't I just style things like normal?"
&lt;/h2&gt;

&lt;p&gt;That's a great question. I'm glad you asked…&lt;/p&gt;

&lt;p&gt;Custom elements give us a way to build complex components with strong API contracts. Component authors can freely refactor internals without changing the public API. That wouldn't be possible if everything was exposed by default. Most things would be a breaking change. 😭&lt;/p&gt;

&lt;p&gt;Style and logic encapsulation has been the holy grail of web development for a long time. Many solutions have been implemented to fake it, but elements have always been susceptible to leaks. The platform has finally given us a tool to solve this problem, so it's worth taking the time to learn and understand it. Once you do, I'm certain you'll embrace it!&lt;/p&gt;

&lt;h2&gt;
  
  
  "Web components sound kinda complicated!"
&lt;/h2&gt;

&lt;p&gt;Perhaps at first, but if you know HTML you're halfway there! Plus, these are &lt;em&gt;standard browser features&lt;/em&gt; and, unlike framework knowledge, learning this stuff will last you a long, long time.&lt;/p&gt;

&lt;p&gt;Think of all the frameworks you've learned over the years and no longer use because their popularity declined. The nice thing about web components is that browsers have committed to supporting them for a long time!&lt;/p&gt;

&lt;p&gt;The spec will surely evolve, but the rug won't be pulled out from under you.&lt;/p&gt;

&lt;h2&gt;
  
  
  "How do you write web components?"
&lt;/h2&gt;

&lt;p&gt;You can write them with plain ol' JavaScript. Or you can use one of the many great component authoring libraries such as &lt;a href="https://lit.dev/" rel="noopener noreferrer"&gt;Google's Lit&lt;/a&gt;. React users might like &lt;a href="https://github.com/matthewp/haunted" rel="noopener noreferrer"&gt;Haunted&lt;/a&gt; for its hook-like syntax. Functional programmers might prefer &lt;a href="https://hybrids.js.org" rel="noopener noreferrer"&gt;Hybrids&lt;/a&gt;. There's also &lt;a href="https://fast.design" rel="noopener noreferrer"&gt;Microsoft's FAST Element&lt;/a&gt; and many others.&lt;/p&gt;

&lt;p&gt;It's worth mentioning that both &lt;a href="https://svelte.dev/docs#run-time-custom-element-api" rel="noopener noreferrer"&gt;Svelte&lt;/a&gt; and &lt;a href="https://v3.vuejs.org/guide/web-components.html#using-custom-elements-in-vue" rel="noopener noreferrer"&gt;Vue&lt;/a&gt; let you generate custom elements too!&lt;/p&gt;

&lt;p&gt;Each library/framework has its own philosophy, but they all generate web components that work in any framework — and in plain ol' HTML pages.&lt;/p&gt;

&lt;p&gt;The beautiful thing about this is you're not forced into a specific flavor. You can write web components the way &lt;em&gt;you&lt;/em&gt; want to write them without sacrificing interoperability!&lt;/p&gt;

&lt;h2&gt;
  
  
  "Does anyone even use web components?"
&lt;/h2&gt;

&lt;p&gt;Yes. &lt;a href="https://arewebcomponentsathingyet.com" rel="noopener noreferrer"&gt;A lot of big companies are using them&lt;/a&gt; and they're becoming ubiquitous. Recently, &lt;a href="https://twitter.com/claviska/status/1452621707576029194" rel="noopener noreferrer"&gt;over 18% of pages&lt;/a&gt; loaded in Chrome registered at least one web component.&lt;/p&gt;

&lt;p&gt;Fun fact: &lt;a href="https://web.dev/ps-on-the-web/" rel="noopener noreferrer"&gt;Adobe is using web components&lt;/a&gt; for the web-based version of Photoshop &lt;a href="https://twitter.com/WestbrookJ/status/1488365582802116610" rel="noopener noreferrer"&gt;and other apps&lt;/a&gt; that used to be desktop-first are transitioning.&lt;/p&gt;

&lt;h2&gt;
  
  
  "But I like my React/Vue/Angular!"
&lt;/h2&gt;

&lt;p&gt;That's cool! I like frameworks too, but I'm tired of rebuilding the same components every couple years. &lt;a href="https://custom-elements-everywhere.com/" rel="noopener noreferrer"&gt;Most frameworks play nicely with web components&lt;/a&gt;, so you can have your cake and eat it too!&lt;/p&gt;

&lt;p&gt;While most web components work perfectly fine as-is inside various frameworks, there is one notable exception.&lt;/p&gt;

&lt;p&gt;React is super popular but &lt;a href="//custom-elements-everywhere.com/#react"&gt;it kinda doesn't get web components&lt;/a&gt;. What can we do?! No worries, &lt;a href="https://twitter.com/claviska/status/1468624872054087680" rel="noopener noreferrer"&gt;React has added experimental support for custom elements&lt;/a&gt; behind a flag. A lot of progress has been made here recently!&lt;/p&gt;

&lt;p&gt;In the meantime, &lt;a href="https://npmjs.com/package/@lit-labs/react" rel="noopener noreferrer"&gt;you can wrap any custom element for React&lt;/a&gt; with a simple function call. This will generate a real React component that wires things up to the underlying custom element. It's like magic! (Tip: the utility has Lit in the name, but it works with all custom elements.)&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Get Started
&lt;/h2&gt;

&lt;p&gt;Hopefully you learned something about web components and shadow DOM in this thread! If you haven't experimented with them yet, why not? It's worth your time to better understand them. Even if you're not developing them yet, you'll likely be using them soon.&lt;/p&gt;

&lt;p&gt;One great way to jump in is by using a library. I happen to be the author of &lt;a href="https://shoelace.style" rel="noopener noreferrer"&gt;Shoelace&lt;/a&gt;, an open source web component library featuring more than 50 useful components.&lt;/p&gt;

&lt;p&gt;This is a great way to get started with custom elements and, because it's open source, you can dive into the code and start learning &lt;em&gt;how&lt;/em&gt; they're made too!&lt;/p&gt;

&lt;p&gt;Have questions? Want to learn more about web components? &lt;a href="https://twitter.com/claviska" rel="noopener noreferrer"&gt;Follow me on Twitter&lt;/a&gt; for more tips, resources, and other web dev stuff!&lt;/p&gt;

</description>
      <category>webcomponents</category>
      <category>javascript</category>
      <category>css</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Flash of Undefined Custom Elements (FOUCE)</title>
      <dc:creator>Cory LaViska</dc:creator>
      <pubDate>Wed, 29 Dec 2021 17:15:00 +0000</pubDate>
      <link>https://dev.to/claviska/flash-of-undefined-custom-elements-fouce-3bp4</link>
      <guid>https://dev.to/claviska/flash-of-undefined-custom-elements-fouce-3bp4</guid>
      <description>&lt;p&gt;Web components are &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry/define" rel="noopener noreferrer"&gt;defined and registered&lt;/a&gt; with JavaScript. Depending on how and when you load the scripts that perform registration, you may see a brief flash of unstyled HTML where your custom elements should be when the page loads. This is not dissimilar to &lt;a href="https://en.wikipedia.org/wiki/Flash_of_unstyled_content" rel="noopener noreferrer"&gt;FOUC&lt;/a&gt;, which occurs when HTML is displayed before the stylesheet has loaded.&lt;/p&gt;

&lt;p&gt;For reference, here's an exaggerated example of three custom elements loading at different intervals.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8to9lnborhq6mn7gahhk.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8to9lnborhq6mn7gahhk.gif" alt="Exaggerated example of FOUCE as custom elements load one by one" width="632" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since the world needs more acronyms, and since one doesn't seem to exist yet, I'm calling this phenomenon FOUCE (rhymes with "spouse"), which stands for &lt;em&gt;Flash of Undefined Custom Elements&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Fortunately, the browser gives us some tools to mitigate it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;:defined&lt;/code&gt; selector
&lt;/h2&gt;

&lt;p&gt;One option is to use the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:defined" rel="noopener noreferrer"&gt;&lt;code&gt;:defined&lt;/code&gt;&lt;/a&gt; CSS pseudo-class to "hide" custom elements that haven't been registered yet. You can scope it to specific tags or you can hide all undefined custom elements as shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:not&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;:defined&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;visibility&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As soon as a custom element is registered, it will immediately appear with all of its styles, effectively eliminating FOUCE. Note the use of &lt;code&gt;visibility: hidden&lt;/code&gt; instead of &lt;code&gt;display: none&lt;/code&gt; to reduce shifting as elements are registered.&lt;/p&gt;

&lt;p&gt;The drawback to this approach is that custom elements can potentially appear one by one instead of all at the same time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F243qaoljsjav4an724xe.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F243qaoljsjav4an724xe.gif" alt="FOUCE is gone, but elements can appear at random as they are defined" width="630" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's certainly a lot better, but can we take things a bit further?&lt;/p&gt;

&lt;h2&gt;
  
  
  Awaiting &lt;code&gt;customElements.whenDefined()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Another option is to use &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry/whenDefined" rel="noopener noreferrer"&gt;&lt;code&gt;customElements.whenDefined()&lt;/code&gt;&lt;/a&gt;, which returns a promise that resolves when the specified element gets registered. You'll probably want to use it with &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled" rel="noopener noreferrer"&gt;&lt;code&gt;Promise.allSettled()&lt;/code&gt;&lt;/a&gt; in case an element fails to load for some reason (&lt;a href="https://twitter.com/WestbrookJ/status/1476286720278683650?s=20" rel="noopener noreferrer"&gt;thanks, Westbrook!&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;A clever way to use this method is to hide the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; with &lt;code&gt;opacity: 0&lt;/code&gt; and add a class that fades it in as soon as all your custom elements are defined.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="nc"&gt;.ready&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;.25s&lt;/span&gt; &lt;span class="n"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;allSettled&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;whenDefined&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;whenDefined&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-card&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;whenDefined&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-rating&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="c1"&gt;// Button, card, and rating are registered now! Add&lt;/span&gt;
  &lt;span class="c1"&gt;// the `ready` class so the UI fades in.&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ready&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In my opinion, this is the better approach because it subtly fades in the entire page as soon as all your custom elements are registered. After all, what's the point of showing the page before it's ready?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fky3dfttnpddx5lv40t60.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fky3dfttnpddx5lv40t60.gif" alt="No more FOUCE because the body fades in only after all elements are defined" width="630" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The drawback, of course, is that you need to keep track of which elements you're using and add them to the list. But this can also be an advantage if your initial UI only requires a handful of custom elements. For example, you can load only the ones you need upfront and let the rest of them load asynchronously to make your page load faster.&lt;/p&gt;

&lt;p&gt;Have you used either of these methods to prevent FOUCE? Have you thought of a better way? &lt;a href="https://twitter.com/claviska" rel="noopener noreferrer"&gt;Let me know on Twitter!&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;small&gt;&lt;br&gt;
  December 30, 2021: The original version of this article mentioned script placement in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; as a method of eliminating FOUCE, but that doesn't work if you're using ES modules. While the approach works for non-modules, I've removed it because it leads to poor page load times and because of the growing ubiquity of ES modules on the Web.&lt;br&gt;
&lt;/small&gt;&lt;/p&gt;

</description>
      <category>webcomponents</category>
      <category>css</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Bulletproof Components</title>
      <dc:creator>Cory LaViska</dc:creator>
      <pubDate>Wed, 08 Dec 2021 22:16:00 +0000</pubDate>
      <link>https://dev.to/claviska/bulletproof-components-300j</link>
      <guid>https://dev.to/claviska/bulletproof-components-300j</guid>
      <description>&lt;p&gt;Somewhere buried in my dusty basement lives a signed copy of Dan Cederholm's classic book &lt;a href="https://simplebits.com/pages/books" rel="noopener noreferrer"&gt;Bulletproof Web Design&lt;/a&gt;. I purchased it during &lt;a href="https://www.abeautifulsite.net/posts/an-event-apart-boston/" rel="noopener noreferrer"&gt;my first trip to An Event Apart&lt;/a&gt; in 2007. This book meant a lot to me back then, and almost 15 years later, many of its concepts still hold true.&lt;/p&gt;

&lt;p&gt;The premise of the book is that designs should be "bulletproof" to accommodate the many ways they can be used.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I'm using the term &lt;em&gt;bulletproof&lt;/em&gt; partly to describe flexibility—in other words, designs for the web that can easily accommodate various text sizes and amounts of content, designs that expand or contract along with whatever is placed within them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I've been a software engineer for many years. More recently, my focus has been on building design systems. Although a lot has changed on the World Wide Web over the last decade, it's easy to recognize that many of the principles in Dan's book also apply to component development.&lt;/p&gt;

&lt;p&gt;But what does a &lt;em&gt;bulletproof component&lt;/em&gt; entail? Before jumping in, let's take a look at why we break down websites and applications into components in the first place.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why do we build components?
&lt;/h2&gt;

&lt;p&gt;Perhaps the most obvious benefit of the component pattern is reusability. Nobody wants to write the same code over and over again. If you end up doing that, have fun finding and updating all of the instances — and variations thereof — that make their way into the wild. This doesn't scale well in small orgs and it falls flat on its face in large ones.&lt;/p&gt;

&lt;p&gt;Components are a vehicle for reusability. Their very nature leads to visual and behavioral consistency. By encapsulating structure, style, and logic into neat little packages, components become powerful tools in your users' arsenal — tools that are convenient to use and a bit harder to misuse.&lt;/p&gt;

&lt;p&gt;When you break a design down into reusable bits, you can assemble, or &lt;em&gt;compose&lt;/em&gt;, those bits to recreate the original design. Better yet, you can create entirely new designs with a lot less effort than building them without composition. Components are the building blocks of your application's foundation.&lt;/p&gt;

&lt;p&gt;It's no secret that I'm a fan of web components (and &lt;a href="https://twitter.com/claviska/status/1466770483739832320" rel="noopener noreferrer"&gt;I'm in good company&lt;/a&gt;), but I'm not here to sell you on web components today. What I will say is that more and more large organizations are leaning on web standards to build and rebuild their design systems in a technology agnostic way. Interoperability falls under the umbrella of reusability, but I think it's an important technical detail to point out.&lt;/p&gt;

&lt;h2&gt;
  
  
  What makes a component bulletproof?
&lt;/h2&gt;

&lt;p&gt;The term &lt;em&gt;bulletproof&lt;/em&gt; might be misleading, so let's consider this passage from Dan's book before we continue:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Out in the nonvirtual world, a bulletproof vest never guarantees complete, 100% protection, but rather being bulletproof is something that's constantly strived for. You're far better off wearing a bulletproof vest than if you weren't.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What we're aiming for with bulletproof components isn't perfection. We're aiming for components that are as intuitive, flexible, and resilient as possible.&lt;/p&gt;

&lt;p&gt;Here are some of the key features that comprise a bulletproof component.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ease of Use
&lt;/h3&gt;

&lt;p&gt;Every component has an API that serves as its primary interface for users. As a component author, many of your users are probably developers which means good DX is critical. Offering consistent, predictable APIs is vital to good DX and therefore a fundamental feature of bulletproof components.&lt;/p&gt;

&lt;p&gt;If you have a library, for example, don't make the &lt;code&gt;size&lt;/code&gt; property accept &lt;code&gt;small|medium|large&lt;/code&gt; in one component and &lt;code&gt;sm|md|lg&lt;/code&gt; in another. As a user, if I've used one or two of your components, I should be able to get the hang of things pretty quickly based on prior experience. Let me build on that knowledge as I go.&lt;/p&gt;

&lt;p&gt;Similarly, I should be able to glance at any component and have a pretty good idea what it does. I know you've documented it, but when I see a component in the wild, I don't want to open the docs unless I absolutely have to.&lt;/p&gt;

&lt;p&gt;It's easy to overload a component with too many features. Oftentimes, that's a sign you should break it down further. Components that take on too much responsibility aren't only harder to use, they're harder to maintain too.&lt;/p&gt;

&lt;h3&gt;
  
  
  Versatility
&lt;/h3&gt;

&lt;p&gt;Components are designed to be reused, so you never know where they'll end up in an application. Plan for this. Expect that users will drop your component into a 100×100 container, a 1200×1200 container, and everything in between. It's not that they're trying to break things, it's that edge cases happen &lt;em&gt;a lot&lt;/em&gt; and it's better to be prepared than to be caught off guard.&lt;/p&gt;

&lt;p&gt;As component developers, we can't predict every possible use case, but we can offer resilience by asking the right questions during development.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does it break when I place it in common locations?&lt;/li&gt;
&lt;li&gt;Does it grow and shrink as the user will expect it to?&lt;/li&gt;
&lt;li&gt;How does it render on a mobile device? A tablet? An extra large screen?&lt;/li&gt;
&lt;li&gt;Is it accessible in all places it's likely to be used in?&lt;/li&gt;
&lt;li&gt;Does it work equally well on touch devices as it does with a mouse?&lt;/li&gt;
&lt;li&gt;Does it work properly as part of a composition?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sometimes it doesn't make sense to test for one thing or another. Use your best judgment and consider the intent. Nobody understands your users better than you, so adapt your questions accordingly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interoperability
&lt;/h3&gt;

&lt;p&gt;As building blocks, components must work across a variety of applications. Unless your organization has a technical mandate, this usually means you need to support a variety of frameworks such as React, Vue, Angular, etc. Interoperability doesn't mean building the same component for every framework you need to support. It means &lt;em&gt;using the same exact components&lt;/em&gt; in every framework.&lt;/p&gt;

&lt;p&gt;This might sound like a web component plug but, realistically speaking, why wouldn't you want your components to work &lt;em&gt;everywhere&lt;/em&gt;? Interop is important because there's a lot of upfront costs, maintenance burdens, and technical debt that comes with building the same thing multiple times.&lt;/p&gt;

&lt;p&gt;Smaller orgs can get away with using a single framework for awhile, but it will eventually catch up to them. Which brings me to the next feature of bulletproof components…&lt;/p&gt;

&lt;h3&gt;
  
  
  Longevity
&lt;/h3&gt;

&lt;p&gt;Congratulations! You've built a component library using your favorite framework. Your users are happy and everything is great. They love the shiny new buttons you gave them!&lt;/p&gt;

&lt;p&gt;[a year or two later]&lt;/p&gt;

&lt;p&gt;Oh look, your favorite framework has evolved. Version 2 is out and that means breaking changes! Quite possibly lots of them. No worries though, version 1 is still, uh, kinda supported. You can probably keep using that for awhile. Wait, what's that? You say a number of teams in the company have already upgraded to version 2?&lt;/p&gt;

&lt;p&gt;Now you have &lt;em&gt;two&lt;/em&gt; component libraries to build and maintain! Or maybe you can endure the challenge of getting everyone in the org to upgrade their old apps. Neither situation is ideal for you, your users, or your organization. Web components can help mitigate this.&lt;/p&gt;

&lt;h3&gt;
  
  
  Documentation
&lt;/h3&gt;

&lt;p&gt;As a component author, I can tell you without question that most developers don't like to read documentation. Nevertheless, good documentation is a necessity for bulletproof components. But what exactly is "good documentation?"&lt;/p&gt;

&lt;p&gt;Good documentation isn't necessarily &lt;em&gt;comprehensive&lt;/em&gt; documentation. While it's certainly important to include all the relevant details of a component's usage, producing superfluous amounts of content is a disservice to your users. People aren't reading your documentation during their coffee break. They have work to do and they want to get it done efficiently. Make it easy for them to find what they need.&lt;/p&gt;

&lt;p&gt;Your component's documentation should be scannable. Tell me what it does. Tell me how to import it. Tell me what props are available. Fill the page with relevant examples and order them from most common to least common, leaving the edge cases for last. Call out important tips and gotchas in context so they're prominent, but not distracting.&lt;/p&gt;

&lt;p&gt;Don't let your content become stale. Nothing is more frustrating than docs that aren't aligned with a component's implementation. Avoid decoupling things that are likely to be forgotten over time.&lt;/p&gt;

&lt;p&gt;Code analyzers can help keep important things such as props, events, and more up to date by bringing the documentation closer to the to code. Remember how I said developers don't like to read? Most don't like to document things, either. Make it harder for them to &lt;em&gt;not&lt;/em&gt; document their changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get Inspired
&lt;/h2&gt;

&lt;p&gt;Building components is an art, and this post certainly isn't definitive nor comprehensive. My intent is to document, through experience and observations, the characteristics that make up &lt;em&gt;bulletproof components&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Consider this an ode to Dan's vision of &lt;em&gt;Bulletproof Web Design&lt;/em&gt; — an extension of a great idea adapted for component development.&lt;/p&gt;

&lt;p&gt;I'm particularly proud of the work I've done on &lt;a href="https://shoelace.style/" rel="noopener noreferrer"&gt;Shoelace&lt;/a&gt;, a library of components that I purposefully maintain with longevity in mind. This project demonstrates all of the principles I've described herein, and I encourage you to use it as inspiration in your own projects. I also encourage you to contribute to the paradigm of bulletproof components through discussion or demonstration &lt;a href="https://twitter.com/claviska" rel="noopener noreferrer"&gt;via Twitter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I can't wait to see what you're working on!&lt;/p&gt;

</description>
      <category>webcomponents</category>
      <category>designsystems</category>
      <category>ui</category>
    </item>
    <item>
      <title>Empowering Design System Users</title>
      <dc:creator>Cory LaViska</dc:creator>
      <pubDate>Mon, 01 Nov 2021 21:21:00 +0000</pubDate>
      <link>https://dev.to/claviska/empowering-design-system-users-4ig7</link>
      <guid>https://dev.to/claviska/empowering-design-system-users-4ig7</guid>
      <description>&lt;p&gt;The question of whether or not component APIs should be locked down at the code level comes up quite a bit. For example, if a button spec only calls for primary, secondary, and tertiary variants, should we still expose &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/::part" rel="noopener noreferrer"&gt;parts&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/--*" rel="noopener noreferrer"&gt;custom properties&lt;/a&gt; so users can make further customization as needed?&lt;/p&gt;

&lt;p&gt;In my experience, the answer is "yes."&lt;/p&gt;

&lt;p&gt;The arguments for locking things down seem to stem from designers who want pixel-perfect results. That's understandable — after all, engineers aren't usually known for their creative skills — but restraints have consequences.&lt;/p&gt;

&lt;p&gt;As design system engineers, we have to face the hard fact that, at some point, users are going to do things that are wrong. It's not our job to prevent them from doing those things. It's our job to give them tools that make it as easy as possible to do things that are &lt;em&gt;right&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This may seem counterintuitive, but requirements change and designs evolve. The best way to experiment with new ideas is to customize what's already there. Neutering a component's API for the sake of design purity means it can no longer be used as a building block for new ideas.&lt;/p&gt;

&lt;p&gt;When your API is too rigid, users will do crazy things to work around it. I've seen developers poke through the shadow root with JavaScript to add custom styles to encapsulated components. In another instance, a consumer built their own version of a component because we didn't expose any CSS parts. All the functionality was there — they just needed different styles.&lt;/p&gt;

&lt;p&gt;You might think you're doing your organization a favor by enforcing standards. I mean, the whole purpose of a design system is to encourage consistency, isn't it?!&lt;/p&gt;

&lt;p&gt;Absolutely, and you can do that with well-designed components and copy + paste examples that demonstrate their correct usage. Assuming developers &lt;em&gt;want&lt;/em&gt; to do the wrong thing is a fallacy. Most of them want to do the right thing and, given the tools, will seldom venture outside the walled garden that is your design system.&lt;/p&gt;

&lt;p&gt;But when users &lt;em&gt;do&lt;/em&gt; need to color outside the lines, taking away their crayons won't stop them. They'll just grab the closest Sharpie and do it anyway.&lt;/p&gt;

&lt;p&gt;Empower your users and you'll save everyone a lot of time and frustration.&lt;/p&gt;




&lt;p&gt;&lt;small&gt;&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;Take advantage of design reviews to understand how consumers are using your components. What customizations have they made? What pain points did they have implementing them? Use this feedback to improve your offering, but &lt;a href="https://dev.to/posts/know-when-to-draw-the-line/"&gt;know when to draw the line&lt;/a&gt;.&lt;/p&gt;



</description>
      <category>designsystem</category>
      <category>design</category>
      <category>webcomponents</category>
    </item>
  </channel>
</rss>
