<?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: Jeremy Keith</title>
    <description>The latest articles on DEV Community by Jeremy Keith (@adactio).</description>
    <link>https://dev.to/adactio</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%2F205225%2F3b2e318c-de68-4e05-9b52-8ebc9b50af52.jpg</url>
      <title>DEV Community: Jeremy Keith</title>
      <link>https://dev.to/adactio</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/adactio"/>
    <language>en</language>
    <item>
      <title>Browser support</title>
      <dc:creator>Jeremy Keith</dc:creator>
      <pubDate>Wed, 05 Jun 2024 08:25:00 +0000</pubDate>
      <link>https://dev.to/adactio/browser-support-1i99</link>
      <guid>https://dev.to/adactio/browser-support-1i99</guid>
      <description>&lt;p&gt;There was a discussion at &lt;a href="https://clearleft.com/"&gt;Clearleft&lt;/a&gt; recently about browser support. &lt;a href="https://clearleft.com/thinking/a-modern-approach-to-browser-support"&gt;Rich has more details&lt;/a&gt; but the gist of it is that, even though we were confident that we had a good approach to browser support, we hadn’t written it down anywhere. Time to fix that.&lt;/p&gt;

&lt;p&gt;This is something I had been thinking about recently anyway—see my post about &lt;a href="https://adactio.com/journal/21128"&gt;Baseline and progressive enhancement&lt;/a&gt;—so it didn’t take too long to put together a document explaining our approach.&lt;/p&gt;

&lt;p&gt;You can find it at &lt;a href="https://browsersupport.clearleft.com/"&gt;browsersupport.clearleft.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We’re not just making it public. We’re releasing it under a &lt;a href="https://creativecommons.org/licenses/by/4.0/"&gt;Creative Commons attribution license&lt;/a&gt;. You can copy this browser-support policy verbatim, you can tweak it, you can change it, you can do what you like. As long you include a credit to Clearleft, you’re all set.&lt;/p&gt;

&lt;p&gt;I think this browser-support policy makes a lot of sense. It certainly beats trying to browser support to specific browsers or version numbers:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We don’t base our browser support on specific browser names and numbers. Instead, our support policy is based on the capabilities of those browsers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The more organisations adopt this approach, the better it is for everyone. Hence the liberal licensing.&lt;/p&gt;

&lt;p&gt;So next time your boss or your client is asking what your official browser-support policy is, feel free to use &lt;a href="https://browsersupport.clearleft.com/"&gt;browsersupport.clearleft.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>clearleft</category>
      <category>browsers</category>
      <category>support</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Applying the four principles of accessibility</title>
      <dc:creator>Jeremy Keith</dc:creator>
      <pubDate>Thu, 30 May 2024 14:38:23 +0000</pubDate>
      <link>https://dev.to/adactio/applying-the-four-principles-of-accessibility-464i</link>
      <guid>https://dev.to/adactio/applying-the-four-principles-of-accessibility-464i</guid>
      <description>&lt;p&gt;&lt;a href="https://www.w3.org/WAI/standards-guidelines/wcag/"&gt;Web Content Accessibility Guidelines&lt;/a&gt;—or WCAG—looks very daunting. It’s a lot to take in. It’s kind of overwhelming. It’s hard to know where to start.&lt;/p&gt;

&lt;p&gt;I recommend taking a deep breath and focusing on &lt;a href="https://www.w3.org/WAI/WCAG22/Understanding/intro#understanding-the-four-principles-of-accessibility"&gt;the four principles of accessibility&lt;/a&gt;. Together they spell out the cutesy acronym POUR:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Perceivable&lt;/li&gt;
&lt;li&gt;Operable&lt;/li&gt;
&lt;li&gt;Understandable&lt;/li&gt;
&lt;li&gt;Robust&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A lot of work has gone into distilling WCAG down to these four guidelines. Here’s how I apply them in my work…&lt;/p&gt;

&lt;h3&gt;
  
  
  Perceivable
&lt;/h3&gt;

&lt;p&gt;I interpret this as:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Content will be legible, regardless of how it is accessed.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The contrast between background and foreground colours will meet the ratios defined in WCAG 2.&lt;/li&gt;
&lt;li&gt;Content will be grouped into semantically-sensible HTML regions such as navigation, main, footer, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Operable
&lt;/h3&gt;

&lt;p&gt;I interpret this as:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Core functionality will be available, regardless of how it is accessed.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I will ensure that interactive controls such as links and form inputs will be navigable with a keyboard.&lt;/li&gt;
&lt;li&gt;Every form control will be labelled, ideally with a visible label.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Understandable
&lt;/h3&gt;

&lt;p&gt;I interpret this as:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Content will make sense, regardless of how it is accessed.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Images will have meaningful alternative text.&lt;/li&gt;
&lt;li&gt;I will make sensible use of heading levels.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where it starts to get quite collaboritive. Working at an agency, there will some parts of website creation and maintenance that will require ongoing accessibility knowledge even when our work is finished.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Images uploaded through a content management system will need sensible alternative text.&lt;/li&gt;
&lt;li&gt;Articles uploaded through a content management system will need sensible heading levels.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Robust
&lt;/h3&gt;

&lt;p&gt;I interpret this as:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Content and core functionality will still work, regardless of how it is accessed.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drop-down controls will use the HTML select element rather than a more fragile imitation.&lt;/li&gt;
&lt;li&gt;I will only use JavaScript to provide functionality that isn’t possible with HTML and CSS alone.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re applying a mindset of progressive enhancement, this part comes for you. If you take a different approach, you’re going to have a bad time.&lt;/p&gt;

&lt;p&gt;Taken together, these four guidelines will get you very far without having to dive too deeply into the rest of WCAG.&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>wcag</category>
      <category>principles</category>
    </item>
    <item>
      <title>Speculation rules</title>
      <dc:creator>Jeremy Keith</dc:creator>
      <pubDate>Tue, 21 May 2024 08:59:24 +0000</pubDate>
      <link>https://dev.to/adactio/speculation-rules-4f95</link>
      <guid>https://dev.to/adactio/speculation-rules-4f95</guid>
      <description>&lt;p&gt;There’s a new addition to the latest version of Chrome called &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Speculation_Rules_API"&gt;speculation rules&lt;/a&gt;. This already existed before with a different syntax, but the new version makes more sense to me.&lt;/p&gt;

&lt;p&gt;Notice that I called this an addition, not a standard. This is &lt;em&gt;not&lt;/em&gt; a web standard, though it may become one in the future. Or it may not. It may wither on the vine and disappear (like &lt;a href="https://killedbygoogle.com/"&gt;most things&lt;/a&gt; that come from Google).&lt;/p&gt;

&lt;p&gt;The gist of it is that you give the browser one or more URLs that the user is likely to navigate to. The browser can then pre-fetch or even pre-render those links, making that navigation really snappy. It’s a replacement for the abandoned &lt;code&gt;link rel="prerender"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Because this is a unilateral feature, I’m not keen on shipping the code to all browsers. The old version of the API required a &lt;code&gt;script&lt;/code&gt; element with a &lt;code&gt;type&lt;/code&gt; value of “speculationrules”. That doesn’t do any harm to browsers that don’t support it—it’s a progressive enhancement. But unlike other progressive enhancements, this isn’t something that will just start working in those other browsers one day. I mean, it might. But until this API is an actual web standard, there’s no guarantee.&lt;/p&gt;

&lt;p&gt;That’s why I was pleased to see that the new version of the API allows you to use an external JSON file with your list of rules.&lt;/p&gt;

&lt;p&gt;I say “rules”, but they’re really more like guidelines. The browser will &lt;a href="https://developer.chrome.com/docs/web-platform/prerender-pages#chrome-limits"&gt;make its own evaluation&lt;/a&gt; based on bandwidth, battery life, and other factors. This feature is more like &lt;code&gt;srcset&lt;/code&gt; than &lt;code&gt;source&lt;/code&gt;: you give the browser some options, but ultimately you can’t force it to do anything.&lt;/p&gt;

&lt;p&gt;I’ve implemented this over on &lt;a href="https://thesession.org/"&gt;The Session&lt;/a&gt;. There’s a JSON file called &lt;code&gt;speculationrules.js&lt;/code&gt; with the simplest of suggestions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "prerender": [{
    "where": {
        "href_matches": "/*"
    },
    "eagerness": "moderate"
  }]
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;eagerness&lt;/code&gt; value of “moderate” says that any link can be pre-rendered if the user hovers over it for 200 milliseconds (the nuclear option would be to use a value of “immediate”).&lt;/p&gt;

&lt;p&gt;I still need to point to that JSON file from my HTML. Usually this would be done with something like a &lt;code&gt;link&lt;/code&gt; element, but for this particular API, I can send a response header instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Speculation-Rules: “/speculationrules.json"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I like that. The response header is being sent to every browser, regardless of whether they support speculation rules or not, but at least it’s just a few bytes. Those other browsers will ignore the header—they won’t download the JSON file.&lt;/p&gt;

&lt;p&gt;Here’s the PHP I added to send that header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;header('Speculation-Rules: "/speculationrules.json"');

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There’s one extra thing I had to do. The JSON file needs to be served with mime-type of “application/speculationrules+json”. Here’s how I set that up in the &lt;code&gt;.conf&lt;/code&gt; file for The Session on Apache:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;IfModule mod_headers.c&amp;gt;
  &amp;lt;FilesMatch "speculationrules.json"&amp;gt;
    Header set Content-type application/speculationrules+json
   &amp;lt;/FilesMatch&amp;gt;
&amp;lt;/IfModule&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A bit of a faff, that.&lt;/p&gt;

&lt;p&gt;You can see it in action on &lt;a href="https://thesession.org/"&gt;The Session&lt;/a&gt;. Open up Chrome or Edge (same same but different), fire up the dev tools and keep the network tab open while you navigate around the site. Notice how hovering over a link will trigger a new network request. Clicking on that link will get you that page lickety-split.&lt;/p&gt;

&lt;p&gt;Mind you, in the case of The Session, the navigations were already really fast—performance is a feature—so it’s hard to guage how much of a practical difference it makes in this case, but it still seems like a no-brainer to me: taking a few minutes to add this to your site is worth doing.&lt;/p&gt;

&lt;p&gt;Oh, there’s one more thing to be aware of when you’re implementing speculation rules. You have the option of excluding URLs from being pre-fetched or pre-rendered. You might need to do this if you’ve got links for adding items to shopping carts, or logging the user out. But my advice would instead be: stop using GET requests for those actions!&lt;/p&gt;

&lt;p&gt;Most of the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Speculation_Rules_API#unsafe_speculative_loading_conditions"&gt;examples given for unsafe speculative loading conditions&lt;/a&gt; are textbook cases of when &lt;em&gt;not&lt;/em&gt; to use links. Links are for navigating. They’re &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Idempotent"&gt;indempotent&lt;/a&gt;. For everthing else, we’ve got forms.&lt;/p&gt;

</description>
      <category>thesession</category>
      <category>performance</category>
      <category>speed</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Baseline progressive enhancement</title>
      <dc:creator>Jeremy Keith</dc:creator>
      <pubDate>Wed, 15 May 2024 16:17:13 +0000</pubDate>
      <link>https://dev.to/adactio/baseline-progressive-enhancement-55b3</link>
      <guid>https://dev.to/adactio/baseline-progressive-enhancement-55b3</guid>
      <description>&lt;p&gt;Support for view transitions for regular websites (as opposed to single-page apps) &lt;a href="https://developer.chrome.com/docs/web-platform/view-transitions/cross-document"&gt;will ship in Chrome 126&lt;/a&gt;. As &lt;a href="https://adactio.com/journal/20195"&gt;someone who’s a big fan&lt;/a&gt;—to put it mildly—I am &lt;em&gt;very&lt;/em&gt; happy about this!&lt;/p&gt;

&lt;p&gt;Hopefully Firefox and Safari won’t be too far behind. But it’s still worth adding view transitions to your website even if not every browser supports them. They’re the perfect example of a progressive enhancement.&lt;/p&gt;

&lt;p&gt;The browsers that don’t yet support view transitions won’t be harmed in any way if you give them the CSS for view transitions. They’ll just ignore it. For users of those browsers, nothing changes.&lt;/p&gt;

&lt;p&gt;Then when those browsers do ship support for view transitions, your website automatically gets an upgrade for those users. Code you’ve already written starts working from one day to the next.&lt;/p&gt;

&lt;p&gt;Don’t wait, is what I’m saying.&lt;/p&gt;

&lt;p&gt;I really like the &lt;a href="https://web.dev/baseline"&gt;Baseline&lt;/a&gt; initiative as a way to track browser support. It’s great to see it in use on MDN and Can I Use. It’s very handy having a glanceable indication of which browser features are newly available and which are widely available.&lt;/p&gt;

&lt;p&gt;But…&lt;/p&gt;

&lt;p&gt;Not all browser features work the same way. For features that work as progressive enhancements you don’t need to wait for them to be widely available.&lt;/p&gt;

&lt;p&gt;Service workers. Preference queries. View transitions.&lt;/p&gt;

&lt;p&gt;If a browser doesn’t support one of those features, that’s fine. Your website won’t break in that browser.&lt;/p&gt;

&lt;p&gt;Now that’s not true of all browser features, particularly some JavaScript APIs. If a feature is critical for your site to function then you definitely want to wait until it’s widely supported.&lt;/p&gt;

&lt;p&gt;Baseline won’t tell you the difference between those two different kinds of features.&lt;/p&gt;

&lt;p&gt;I don’t want Baseline to get too complicated. Like I said, I really like how it’s nice and glanceable right now. But it would be nice if there way some indication that a newly-available feature is a progressive enhancement.&lt;/p&gt;

&lt;p&gt;For now it’s up to us to make that distinction. So don’t fall into the trap of thinking that just because a feature isn’t listed as widely-available you can’t use it yet.&lt;/p&gt;

&lt;p&gt;Really you want to ask two questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How widely available is this feature?&lt;/li&gt;
&lt;li&gt;Can this feature be used as a progressive enhancement?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If Baseline tells you that the answer to the first question is “newly-available”, move on to the second question. If the answer to that is “no, it can’t be used as a progressive enhancement”, don’t ship that feature in production just yet.&lt;/p&gt;

&lt;p&gt;But if the answer to that second question is “hell yeah, it’s a progressive enhancement!” then go for it, regardless of the answer to the first question.&lt;/p&gt;

&lt;p&gt;Y’know, there’s a real irony in a common misunderstanding around progressive enhancement: some people seem to think it’s about &lt;em&gt;not&lt;/em&gt; being able to use advanced browser features. In reality it’s the opposite. Progressive enhancement allows you to use advanced browser features even before they’re widely supported.&lt;/p&gt;

</description>
      <category>baseline</category>
      <category>progressive</category>
      <category>enhancement</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Securing client-side JavaScript</title>
      <dc:creator>Jeremy Keith</dc:creator>
      <pubDate>Sun, 05 May 2024 10:43:09 +0000</pubDate>
      <link>https://dev.to/adactio/securing-client-side-javascript-2dhk</link>
      <guid>https://dev.to/adactio/securing-client-side-javascript-2dhk</guid>
      <description>&lt;p&gt;I mentioned that &lt;a href="https://adactio.com/journal/21078"&gt;I overhauled the JavaScript&lt;/a&gt; on &lt;a href="https://thesession.org/"&gt;The Session&lt;/a&gt; recently. That wasn’t just so that I could mess about with &lt;a href="https://adactio.com/journal/20618"&gt;HTML web components&lt;/a&gt;. I’d been meaning to consolidate some scripts for a while.&lt;/p&gt;

&lt;p&gt;Some of the pages on the site had inline scripts. These were usually one-off bits of functionality. But their presence meant that my &lt;a href="https://content-security-policy.com/"&gt;content security policy&lt;/a&gt; wasn’t as tight as it could’ve been.&lt;/p&gt;

&lt;p&gt;Being a community website, The Session accepts input from its users. Literally. I do everything I can to sanitise that input. It would be ideal if I could make sure that any JavaScript that slipped by wouldn’t execute. But as long as I had my own inline scripts, my content security policy had to allow them to be executed with &lt;a href="https://content-security-policy.com/unsafe-inline/"&gt;&lt;code&gt;script-src: unsafe-inline&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That’s why I wanted to refactor the JavaScript on my site and move everything to external JavaScript files.&lt;/p&gt;

&lt;p&gt;In the end I got close, but there are still one or two pages with internal scripts. But that’s okay. I found a way to have my content security policy cake and eat it.&lt;/p&gt;

&lt;p&gt;In my content security policy header I can specifiy that inline scripts are allowed, but only if they have a one-time token specified.&lt;/p&gt;

&lt;p&gt;This one-time token is called &lt;a href="https://content-security-policy.com/nonce/"&gt;a nonce&lt;/a&gt;. No, really. Stop sniggering. Naming things is hard. And occassionally unintentionally hilarious.&lt;/p&gt;

&lt;p&gt;On the server, every time a page is requested it gets sent back with a header like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;content-security-policy: script-src 'self' 'nonce-Cbb4kxOXIChJ45yXBeaq/w=='

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That gobbledegook string is generated randomly every time. I’m using PHP to do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;base64_encode(openssl_random_pseudo_bytes(16))

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then in the HTML I use the same string in any inline scripts on the page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script nonce="Cbb4kxOXIChJ45yXBeaq/w=="&amp;gt;
…
&amp;lt;/script&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yes, HTML officially has &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/nonce"&gt;an attribute called &lt;code&gt;nonce&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It’s working a treat. &lt;a href="https://securityheaders.com/?q=https://thesession.org"&gt;The security headers for The Session&lt;/a&gt; are looking good. I have some more stuff in my content security policy—&lt;a href="https://report-uri.com/home/analyse/https%3A%2F%2Fthesession.org%2F"&gt;check out the details&lt;/a&gt; if you’re interested.&lt;/p&gt;

&lt;p&gt;I initially thought I’d have to make an exception for &lt;a href="https://thesession.org/offline"&gt;the custom offline page on The Session&lt;/a&gt;. After all, that’s only going to be accessed when there is no server involved so I wouldn’t be able to generate a one-time token. And I definitely needed an inline script on that page in order to generate a list of previously-visited pages stored in a cache.&lt;/p&gt;

&lt;p&gt;But then I realised that everything would be okay. When the offline page is cached, its headers are cached too. So the one-time token in the content security policy header still matches the one-time token used in the page.&lt;/p&gt;

&lt;p&gt;Most pages on &lt;a href="https://thesession.org/"&gt;The Session&lt;/a&gt; don’t have any inline scripts. For a while, &lt;em&gt;every&lt;/em&gt; page had an inline script in the &lt;code&gt;head&lt;/code&gt; of the document like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script nonce="Cbb4kxOXIChJ45yXBeaq/w=="&amp;gt;
document.documentElement.classList.add('hasJS');
&amp;lt;/script&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is something I’ve been doing for years: using JavaScript to add a class to the HTML. Then I can use the presence or absence of that class to show or hide elements that require JavaScript. I have another class called &lt;code&gt;requiresJS&lt;/code&gt; that I put on any elements that need JavaScript to work (like buttons for copying to the clipboard, for example).&lt;/p&gt;

&lt;p&gt;Then in my CSS I’d write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:not(.hasJS) .requiresJS {
 display: none;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the &lt;code&gt;hasJS&lt;/code&gt; class isn’t set, hide any elements with the &lt;code&gt;requiresJS&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;I decided to switch over to using &lt;a href="https://ryanmulligan.dev/blog/detect-js-support-in-css/"&gt;a scripting media query&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;@media (scripting: none) {
  .requiresJS {
   display: none;
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This isn’t bulletproof by any means. It doesn’t account for browser extensions that disable JavaScript and it won’t get executed at all in older browsers. But I’m okay with that. I’ve put &lt;a href="https://adactio.com/journal/20999"&gt;the destructive action in the more modern CSS&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I feel that the more risky action (hiding content) should belong to the more complex selector.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This means that there are situations where elements that require JavaScript will be visible, even if JavaScript isn’t available. But I’d rather that than the other way around: if those elements were hidden from browsers that &lt;em&gt;could&lt;/em&gt; execute JavaScript, that would be worse.&lt;/p&gt;

</description>
      <category>thesession</category>
      <category>security</category>
      <category>frontend</category>
      <category>development</category>
    </item>
    <item>
      <title>My approach to HTML web components</title>
      <dc:creator>Jeremy Keith</dc:creator>
      <pubDate>Mon, 29 Apr 2024 15:37:36 +0000</pubDate>
      <link>https://dev.to/adactio/my-approach-to-html-web-components-5h9</link>
      <guid>https://dev.to/adactio/my-approach-to-html-web-components-5h9</guid>
      <description>&lt;p&gt;I’ve been deep-diving into &lt;a href="https://adactio.com/journal/20618"&gt;HTML web components&lt;/a&gt; over the past few weeks. I decided to refactor the JavaScript on &lt;a href="https://thesession.org/"&gt;The Session&lt;/a&gt; to use custom elements wherever it made sense.&lt;/p&gt;

&lt;p&gt;I really enjoyed doing this, even though the end result for users is exactly the same as before. This was one of those refactors that was for me, and also for future me. The front-end codebase looks a lot more understandable and therefore maintainable.&lt;/p&gt;

&lt;p&gt;Most of the JavaScript on &lt;a href="https://thesession.org/"&gt;The Session&lt;/a&gt; is good ol’ DOM scripting. Listen for events; when an event happens, make some update to some element. It’s the kind of stuff we might have used jQuery for in the past.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gomakethings.com/"&gt;Chris&lt;/a&gt; invoked &lt;a href="https://en.wikipedia.org/wiki/Betteridge%27s_law_of_headlines"&gt;Betteridge’s law of headlines&lt;/a&gt; recently by asking &lt;a href="https://gomakethings.com/will-web-components-replace-react-and-vue/"&gt;&lt;cite&gt;Will Web Components replace React and Vue?&lt;/cite&gt;&lt;/a&gt; I agree with his assessment. The reactivity you get with full-on frameworks isn’t something that web components offer. But I do think web components can replace jQuery and other approaches to scripting the DOM.&lt;/p&gt;

&lt;p&gt;I’ve written about my preferred way to do DOM scripting: &lt;a href="https://adactio.com/journal/20551"&gt;&lt;code&gt;element.target.closest&lt;/code&gt;&lt;/a&gt;. One of the advantages to that approach is that even if the DOM gets updated—perhaps via Ajax—the event listening will still work.&lt;/p&gt;

&lt;p&gt;Well, this is &lt;em&gt;exactly&lt;/em&gt; the kind of thing that custom elements take care of for you. The &lt;code&gt;connectedCallback&lt;/code&gt; method gets fired whenever an instance of the custom element is added to the document, regardless of whether that’s in the initial page load or later in an Ajax update.&lt;/p&gt;

&lt;p&gt;So my client-side scripting style has updated over time:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Adding event handlers directly to elements.&lt;/li&gt;
&lt;li&gt;Adding event handlers to the document and using &lt;code&gt;event.target.closest&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Wrapping elements in a web component that handles the event listening.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of these progressions were particularly ground-breaking or allowed me to do anything I couldn’t do previously. But each progression improved the resilience and maintainability of my code.&lt;/p&gt;

&lt;p&gt;Like Chris, I’m using web components to progressively enhance what’s already in the markup. In fact, looking at the code that Chris is sharing, I think we may be writing some very similar web components!&lt;/p&gt;

&lt;p&gt;A few patterns have emerged for me…&lt;/p&gt;

&lt;h3&gt;
  
  
  Naming custom elements
&lt;/h3&gt;

&lt;p&gt;Naming things is famously hard. Every time you make a new custom element you have to give it a name that includes a hyphen. I settled on the convention of using the first part of the name to echo the element being enhanced.&lt;/p&gt;

&lt;p&gt;If I’m adding an enhancement to a &lt;code&gt;button&lt;/code&gt; element, I’ll wrap it in a custom element that starts with &lt;code&gt;button-&lt;/code&gt;. I’ve now got custom elements like &lt;code&gt;button-geolocate&lt;/code&gt;, &lt;code&gt;button-confirm&lt;/code&gt;, &lt;code&gt;button-clipboard&lt;/code&gt; and so on.&lt;/p&gt;

&lt;p&gt;Likewise if the custom element is enhancing a link, it will begin with &lt;code&gt;a-&lt;/code&gt;. If it’s enhancing a form, it will begin with &lt;code&gt;form-&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The name of the custom element tells me how it’s expected to be used. If I find myself wrapping a &lt;code&gt;div&lt;/code&gt; with &lt;code&gt;button-geolocate&lt;/code&gt; I shouldn’t be surprised when it doesn’t work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Naming attributes
&lt;/h3&gt;

&lt;p&gt;You can use any attributes you want on a web component. You made up the name of the custom element and you can make up the names of the attributes too.&lt;/p&gt;

&lt;p&gt;I’m a little nervous about this. What if HTML ends up with a new global attribute in the future that clashes with something I’ve invented? It’s unlikely but it still makes me wary.&lt;/p&gt;

&lt;p&gt;So I use &lt;code&gt;data-&lt;/code&gt; attributes. I’ve already got a hyphen in the name of my custom element, so it makes sense to have hyphens in my attributes too. And by using &lt;code&gt;data-&lt;/code&gt; attributes, the browser gives me automatic reflection of the value in &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dataset"&gt;the &lt;code&gt;dataset&lt;/code&gt; property&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Instead of getting a value with &lt;code&gt;this.getAttribute('maximum')&lt;/code&gt; I get to use &lt;code&gt;this.dataset.maximum&lt;/code&gt;. Nice and neat.&lt;/p&gt;

&lt;h3&gt;
  
  
  The single responsibility principle
&lt;/h3&gt;

&lt;p&gt;My favourite web components aren’t all-singing, all-dancing powerhouses. Rather they do one thing, often a very simple thing.&lt;/p&gt;

&lt;p&gt;Here are some examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Jason’s &lt;a href="https://github.com/jgarber623/aria-collapsible"&gt;&lt;code&gt;aria-collapsable&lt;/code&gt;&lt;/a&gt; for toggling the display of one element when you click on another.&lt;/li&gt;
&lt;li&gt;David’s &lt;a href="https://github.com/daviddarnes/play-button"&gt;&lt;code&gt;play-button&lt;/code&gt;&lt;/a&gt; for adding a play button to an &lt;code&gt;audio&lt;/code&gt; or &lt;code&gt;video&lt;/code&gt; element.&lt;/li&gt;
&lt;li&gt;Chris’s &lt;a href="https://gomakethings.com/html-web-components/"&gt;&lt;code&gt;ajax-form&lt;/code&gt;&lt;/a&gt; for sending a form via Ajax instead of a full page refresh.&lt;/li&gt;
&lt;li&gt;Jim’s &lt;a href="https://blog.jim-nielsen.com/2023/html-web-components-an-example/"&gt;&lt;code&gt;user-avatar&lt;/code&gt;&lt;/a&gt; for adding a tooltip to an image.&lt;/li&gt;
&lt;li&gt;Zach’s &lt;a href="https://github.com/zachleat/table-saw"&gt;&lt;code&gt;table-saw&lt;/code&gt;&lt;/a&gt; for making tables responsive.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of those are &lt;a href="https://adactio.com/journal/20618"&gt;HTML web components&lt;/a&gt; in that they &lt;em&gt;extend&lt;/em&gt; your existing markup rather than JavaScript web components that are used to &lt;em&gt;replace&lt;/em&gt; HTML. All of those are also unambitious by design. They each do one thing and one thing only.&lt;/p&gt;

&lt;p&gt;But what if my web component needs to do two things?&lt;/p&gt;

&lt;p&gt;I make two web components.&lt;/p&gt;

&lt;p&gt;The beauty of custom elements is that they can be used just like regular HTML elements. And the beauty of HTML is that it’s composable.&lt;/p&gt;

&lt;p&gt;What if you’ve got some text that you want to be a level-three heading &lt;em&gt;and&lt;/em&gt; also a link? You don’t bemoan the lack of an element that does both things. You wrap an &lt;code&gt;a&lt;/code&gt; element in an &lt;code&gt;h3&lt;/code&gt; element.&lt;/p&gt;

&lt;p&gt;The same goes for custom elements. If I find myself adding multiple behaviours to a single custom element, I stop and ask myself if this should be multiple custom elements instead.&lt;/p&gt;

&lt;p&gt;Take some of those &lt;code&gt;button-&lt;/code&gt; elements I mentioned earlier. One of them copies text to the clipboard, &lt;code&gt;button-clipboard&lt;/code&gt;. Another throws up a confirmation dialog to complete an action, &lt;code&gt;button-confirm&lt;/code&gt;. Suppose I want users to confirm when they’re copying something to their clipboard (not a realistic example, I admit). I don’t have to create a new hybrid web component. Instead I wrap the &lt;code&gt;button&lt;/code&gt; in the two existing custom elements.&lt;/p&gt;

&lt;p&gt;Rather than having a few powerful web components, I like having lots of simple web components. The power comes with how they’re combined. Like Unix pipes. And it has the added benefit of stopping my code getting too complex and hard to understand.&lt;/p&gt;

&lt;h3&gt;
  
  
  Communicating across components
&lt;/h3&gt;

&lt;p&gt;Okay, so I’ve broken all of my behavioural enhancements down into single-responsibility web components. But what if one web component needs to have awareness of something that happens in another web component?&lt;/p&gt;

&lt;p&gt;Here’s an example from The Session: the results page when you search for &lt;a href="https://thesession.org/sessions/search?q=London+England"&gt;sessions in London&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There’s a map. That’s one web component. There’s a list of locations. That’s another web component. There are links for traversing backwards and forwards through the locations via Ajax. Those links are in web components too.&lt;/p&gt;

&lt;p&gt;I want the map to update when the list of locations changes. Where should that logic live? How do I get the list of locations to communicate with the map?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Events/Creating_and_triggering_events"&gt;Events&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;When a list of locations is added to the document, it emits a custom event that bubbles all the way up. In fact, that’s all this component does.&lt;/p&gt;

&lt;p&gt;You can call the event anything you want. It could be a &lt;code&gt;newLocations&lt;/code&gt; event. That event is dispatched in the &lt;code&gt;connectedCallback&lt;/code&gt; of the component.&lt;/p&gt;

&lt;p&gt;Meanwhile in the map component, an event listener listens for any &lt;code&gt;newLocations&lt;/code&gt; events on the document. When that event handler is triggered, the map updates.&lt;/p&gt;

&lt;p&gt;The web component that lists locations has no idea that there’s a map on the same page. It doesn’t need to. It just needs to dispatch its event, no questions asked.&lt;/p&gt;

&lt;p&gt;There’s nothing specific to web components here. Event-driven programming is a tried and tested approach. It’s just a little easier to do thanks to the &lt;code&gt;connectedCallback&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;I’m documenting all this here as a snapshot of my current thinking on &lt;a href="https://adactio.com/journal/20618"&gt;HTML web components&lt;/a&gt; when it comes to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;naming custom elements,&lt;/li&gt;
&lt;li&gt;naming attributes,&lt;/li&gt;
&lt;li&gt;the single responsibility principle, and&lt;/li&gt;
&lt;li&gt;communicating across components.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I may well end up changing my approach again in the future. For now though, these ideas are serving me well.&lt;/p&gt;

</description>
      <category>html</category>
      <category>webcomponents</category>
      <category>progressive</category>
      <category>enhancement</category>
    </item>
    <item>
      <title>Displaying HTML web components</title>
      <dc:creator>Jeremy Keith</dc:creator>
      <pubDate>Wed, 17 Apr 2024 09:37:10 +0000</pubDate>
      <link>https://dev.to/adactio/displaying-html-web-components-29c0</link>
      <guid>https://dev.to/adactio/displaying-html-web-components-29c0</guid>
      <description>&lt;p&gt;Those &lt;a href="https://adactio.com/journal/21045"&gt;HTML web components I made for date inputs&lt;/a&gt; are very simple. All they do is slightly extend the behaviour of the existing &lt;code&gt;input&lt;/code&gt; elements.&lt;/p&gt;

&lt;p&gt;This would be the ideal use-case for &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/is"&gt;the &lt;code&gt;is&lt;/code&gt; attribute&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;&amp;lt;input is="input-date-future" type="date"&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alas, Apple have gone on record to say that &lt;a href="https://github.com/WICG/webcomponents/issues/509"&gt;they will &lt;em&gt;never&lt;/em&gt; ship support for customized built-in elements&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So instead we have to make &lt;a href="https://adactio.com/journal/20618"&gt;HTML web components&lt;/a&gt; by wrapping existing elements in new custom elements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;input-date-future&amp;gt;
  &amp;lt;input type="date"&amp;gt;
&amp;lt;input-date-future&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The end result is the same. Mostly.&lt;/p&gt;

&lt;p&gt;Because there’s now an additional element in the DOM, there could be unexpected styling implications. Like, suppose the original element was direct child of a flex or grid container. Now that will no longer be true.&lt;/p&gt;

&lt;p&gt;So something I’ve started doing with HTML web components like these is adding something like this inside the &lt;code&gt;connectedCallback&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;connectedCallback() {
    this.style.display = 'contents';
  …
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells the browser that, as far as styling is concerned, there’s nothing to see here. Move along.&lt;/p&gt;

&lt;p&gt;Or you could (and probably should) do it in your stylesheet instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;input-date-future {
  display: contents;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just to be clear, you should only use &lt;code&gt;display: contents&lt;/code&gt; if your HTML web component is augmenting what’s &lt;em&gt;within&lt;/em&gt; it. If you add any behaviours or styling to the custom element itself, then don’t add this style declaration.&lt;/p&gt;

&lt;p&gt;It’s a bit of a hack to work around the lack of universal support for the &lt;code&gt;is&lt;/code&gt; attribute, but it’ll do.&lt;/p&gt;

</description>
      <category>html</category>
      <category>webcomponents</category>
      <category>progressive</category>
      <category>enhancement</category>
    </item>
    <item>
      <title>Hanging punctuation in CSS</title>
      <dc:creator>Jeremy Keith</dc:creator>
      <pubDate>Wed, 03 Apr 2024 08:19:15 +0000</pubDate>
      <link>https://dev.to/adactio/hanging-punctuation-in-css-dp3</link>
      <guid>https://dev.to/adactio/hanging-punctuation-in-css-dp3</guid>
      <description>&lt;p&gt;There’s a lovely CSS property called &lt;code&gt;hanging-punctuation&lt;/code&gt;. You can use it to do &lt;a href="https://en.wikipedia.org/wiki/Hanging_punctuation"&gt;exactly what the name suggests&lt;/a&gt; and exdent punctuation marks such as opening quotes.&lt;/p&gt;

&lt;p&gt;Here’s one way to apply it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;html {
  hanging-punctuation: first last;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Any punctuation marks at the beginning or end of a line will now hang over the edge, leaving you with nice clean blocks of text; no ragged edges.&lt;/p&gt;

&lt;p&gt;Right now it’s &lt;a href="https://caniuse.com/css-hanging-punctuation"&gt;only supported in Safari&lt;/a&gt; but there’s no reason not to use it. It’s a perfect example of progressive enhancement. One line of CSS to tidy things up for the browsers that support it and leave things exactly as they are for the browsers that don’t.&lt;/p&gt;

&lt;p&gt;But when I used this over on &lt;a href="https://thesession.org/"&gt;The Session&lt;/a&gt; I noticed an unintended side-effect. Because I’m applying the property globally, it’s also acting on form fields. If the text inside a form field starts with a quotation mark or some other piece of punctuation, it’s shunted off to the side and hidden.&lt;/p&gt;

&lt;p&gt;Here’s the fix I used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;input, textarea {
  hanging-punctuation: none;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s a small little gotcha but I figured I’d share it in case it helps someone else out.&lt;/p&gt;

</description>
      <category>css</category>
      <category>hanging</category>
      <category>punctuation</category>
      <category>typography</category>
    </item>
    <item>
      <title>The complete line-up for Patterns Day …and a workshop!</title>
      <dc:creator>Jeremy Keith</dc:creator>
      <pubDate>Thu, 16 Nov 2023 14:46:58 +0000</pubDate>
      <link>https://dev.to/adactio/the-complete-line-up-for-patterns-day-and-a-workshop-l8f</link>
      <guid>https://dev.to/adactio/the-complete-line-up-for-patterns-day-and-a-workshop-l8f</guid>
      <description>&lt;p&gt;The line-up for &lt;a href="https://patternsday.com/"&gt;Patterns Day&lt;/a&gt; is complete! You’ll be hearing from &lt;a href="https://patternsday.com/#speakers"&gt;eight fantastic speakers&lt;/a&gt; on March 7th 2024 here in Brighton.&lt;/p&gt;

&lt;p&gt;I really like the mix of speakers we’ve got…&lt;/p&gt;

&lt;p&gt;Half of the speakers will be sharing what they’ve learned from design systems in their organisations: Débora from LEGO, Mary from the Financial Times, Yolijn from the Dutch government, and Samantha from University College London. That’s a good spread of deep dives.&lt;/p&gt;

&lt;p&gt;The other half of the speakers can go broad across design systems in general: Vitaly on design patterns, Rich on typography, Geri on accessibility, and Jina on …well, absolutely everything to do with design systems!&lt;/p&gt;

&lt;p&gt;I’m so happy that I could get the line-up to have this mix. If you have any interest in design systems at all—whether it’s as a designer, a developer, a product manager, or anything else—you won’t want to miss this. &lt;a href="https://ti.to/clearleft/patternsday2024"&gt;Early bird tickets are £225&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But wait! That’s not all. If you &lt;em&gt;really&lt;/em&gt; want to dive deep into interface design patterns, then stick around. The day after Patterns Day, &lt;a href="https://patternsday.com/#workshop"&gt;Vitaly is running a one-day workshop&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In this in-person workshop with Vitaly Friedman, UX consultant and creative lead behind Smashing Magazine, we’ll dive deep into dissecting how to solve complex design problems. Whether you’re working on a complex nested multi-level navigation or creating enterprise grade tables, this workshop will give you the tools you need to excel at your work.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Places are limited. There isn’t room for everyone who’s going to be at Patterns Day, so if you—and your team—want to learn design pattern kung-fu from the master, &lt;a href="https://ti.to/clearleft/patternsday2024"&gt;get your workshop ticket now&lt;/a&gt;! Workshop tickets are £445.&lt;/p&gt;

</description>
      <category>patternsday</category>
      <category>conferences</category>
      <category>events</category>
      <category>brighton</category>
    </item>
    <item>
      <title>HTML web components</title>
      <dc:creator>Jeremy Keith</dc:creator>
      <pubDate>Thu, 09 Nov 2023 17:03:47 +0000</pubDate>
      <link>https://dev.to/adactio/html-web-components-4opj</link>
      <guid>https://dev.to/adactio/html-web-components-4opj</guid>
      <description>&lt;p&gt;Web components have been around for quite a while, but it feels like they’re having a bit of a moment right now.&lt;/p&gt;

&lt;p&gt;It turns out that the best selling point for web components was “wait and see.” For everyone who didn’t see the benefit of web components over being locked into a specific framework, time is proving to be a great teacher.&lt;/p&gt;

&lt;p&gt;It’s not just that &lt;a href="https://www.abeautifulsite.net/posts/a-web-component-story/"&gt;web components are portable&lt;/a&gt;. They’re also web standards, which means they’ll be around as long as web browsers. No framework can make that claim. As Jake Lazaroff puts it, &lt;a href="https://jakelazaroff.com/words/web-components-will-outlive-your-javascript-framework/"&gt;&lt;cite&gt;web components will outlive your JavaScript framework&lt;/cite&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At this point React is legacy technology, like Angular. Lots of people are still using it, but nobody can quite remember why. The decision-makers in organisations who chose to build everything with React have long since left. People starting new projects who still decide to build on React are doing it largely out of habit.&lt;/p&gt;

&lt;p&gt;Others are making more sensible judgements and, having been bitten by lock-in in the past, are now giving web components a go.&lt;/p&gt;

&lt;p&gt;If you’re one of those people making the move from React to web components, there’ll certainly be a bit of a learning curve, but that would be true of any technology change.&lt;/p&gt;

&lt;p&gt;I have a suggestion for you if you find yourself in this position. Try not to bring React’s mindset with you.&lt;/p&gt;

&lt;p&gt;I’m talking about the way React components are composed. There’s often lots of props doing heavy lifting. The actual component element itself might be empty.&lt;/p&gt;

&lt;p&gt;If you want to apply that model to web components, you can. Lots of people do. It’s not unusual to see web components in the wild that look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;my-component&amp;gt;&amp;lt;/my-component&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The custom element is just a shell. All the actual power is elsewhere. It’s in the JavaScript that does all kinds of clever things with the shadow DOM, templates, and slots.&lt;/p&gt;

&lt;p&gt;There is another way. Ask, &lt;a href="https://sfba.social/@fonts/111211813228079834"&gt;as Robin does&lt;/a&gt;, “what would HTML do?”&lt;/p&gt;

&lt;p&gt;Think about composibility with existing materials. Do you really need to invent an entirely new component from scratch? Or can you use HTML up until it reaches its limit and then &lt;em&gt;enhance&lt;/em&gt; the markup?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://buttondown.email/cascade/archive/005-why-web-components/"&gt;Robin writes&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I don’t think we should see web components like the ones you might find in a huge monolithic React app: your Button or Table or Input components. Instead, I’ve started to come around and see Web Components as filling in the blanks of what we can do with hypertext: they’re really just small, reusable chunks of code that extends the language of HTML.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Dave talks about how web components can be &lt;a href="https://daverupert.com/2021/10/html-with-superpowers/"&gt;HTML with superpowers&lt;/a&gt;. I think that’s a good attitude to have. Instead of all-singing, all-dancing web components, it feels a lot more elegant to use web components to augment your existing markup with just enough extra behaviour.&lt;/p&gt;

&lt;p&gt;Where does the shadow DOM come into all of this? It doesn’t. And that’s okay. I’m not saying it should be avoided completely, but it should be a last resort. See how far you can get with the composibility of regular HTML first.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://meyerweb.com/eric/thoughts/2023/11/01/blinded-by-the-light-dom/"&gt;Eric described his recent epiphany with web components&lt;/a&gt;. He created a &lt;code&gt;super-slider&lt;/code&gt; custom element that wraps around an existing &lt;code&gt;label&lt;/code&gt; and &lt;code&gt;input type="range"&lt;/code&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You just take some normal HTML markup, wrap it with a custom element, and then write some JS to add capabilities which you can then style with regular CSS!  Everything’s of the Light Side of the Web.  No need to pierce the Vale of Shadows or whatever.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When you wrap some existing markup in a custom element and then apply some new behaviour with JavaScript, technically you’re not doing anything you couldn’t have done before with some DOM traversal and event handling. But it’s less fragile to do it with a web component. It’s portable. It obeys the single responsibility principle. It only does one thing but it does it well.&lt;/p&gt;

&lt;p&gt;Jim created &lt;a href="https://blog.jim-nielsen.com/2023/web-components-icon-galleries/"&gt;an &lt;code&gt;icon-list&lt;/code&gt; custom element&lt;/a&gt; that wraps around a regular &lt;code&gt;ul&lt;/code&gt; populated with &lt;code&gt;li&lt;/code&gt; elements. But he feels almost bashful about even calling it a web component:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Maybe I shouldn’t be using the term “web component” for what I’ve done here. I’m not using shadow DOM. I’m not using the templates or slots. I’m really only using custom elements to attach functionality to a specific kind of component.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I think what Eric and Jim are doing is exemplary. See also &lt;a href="https://www.zachleat.com/web/?category=web-components"&gt;Zach’s web components&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At the end of &lt;a href="https://meyerweb.com/eric/thoughts/2023/11/01/blinded-by-the-light-dom/"&gt;his post&lt;/a&gt;, Eric says he’d like a nice catchy term for these kinds of web components. In &lt;a href="https://github.com/davatron5000/awesome-standalones#element-extensions"&gt;Dave’s catalogue of web components&lt;/a&gt;, they’re called “element extensions.” I like that. It’s pretty catchy.&lt;/p&gt;

&lt;p&gt;Or we could call them “HTML web components.” If your custom element is empty, it’s not an HTML web component. But if you’re using a custom element to extend existing markup, that’s an HTML web component.&lt;/p&gt;

&lt;p&gt;React encouraged a mindset of replacement: “forgot what browsers can do; do everything in a React component instead, even if you’re reinventing the wheel.”&lt;/p&gt;

&lt;p&gt;HTML web components encourage a mindset of augmentation instead.&lt;/p&gt;

</description>
      <category>webcomponents</category>
      <category>progressive</category>
      <category>enhancement</category>
      <category>frontend</category>
    </item>
    <item>
      <title>event.target.closest</title>
      <dc:creator>Jeremy Keith</dc:creator>
      <pubDate>Thu, 12 Oct 2023 09:09:30 +0000</pubDate>
      <link>https://dev.to/adactio/eventtargetclosest-114g</link>
      <guid>https://dev.to/adactio/eventtargetclosest-114g</guid>
      <description>&lt;p&gt;&lt;a href="https://mastodon.social/@Meyerweb/111219441257570897"&gt;Eric mentioned the JavaScript &lt;code&gt;closest&lt;/code&gt; method&lt;/a&gt;. I use it all the time.&lt;/p&gt;

&lt;p&gt;When I wrote the book &lt;a href="https://domscripting.com/"&gt;DOM Scripting&lt;/a&gt; back in 2005, I’d estimate that 90% of the JavaScript I was writing boiled down to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Find these particular elements in the DOM and&lt;/li&gt;
&lt;li&gt;When the user clicks on one of them, do something.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It wasn’t just me either. I reckon that was 90% of most JavaScript on the web: progressive disclosure widgets, accordions, carousels, and so on.&lt;/p&gt;

&lt;p&gt;That’s one of the reasons why jQuery became so popular. That first step (“find these particular elements in the DOM”) used to be a finicky affair involving &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/getElementsByTagName"&gt;&lt;code&gt;getElementsByTagName&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment/getElementById"&gt;&lt;code&gt;getElementById&lt;/code&gt;&lt;/a&gt;, and other long-winded DOM methods. jQuery came along and allowed us to use CSS selectors.&lt;/p&gt;

&lt;p&gt;These days, we don’t need jQuery for that because we’ve got &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector"&gt;&lt;code&gt;querySelector&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll"&gt;&lt;code&gt;querySelectorAll&lt;/code&gt;&lt;/a&gt; (and we can &lt;a href="https://adactio.com/journal/10806"&gt;thank jQuery&lt;/a&gt; for their existence).&lt;/p&gt;

&lt;p&gt;Let’s say you want to add some behaviour to every &lt;code&gt;button&lt;/code&gt; element with a &lt;code&gt;class&lt;/code&gt; of &lt;code&gt;special&lt;/code&gt;. Or maybe you use a &lt;code&gt;data-&lt;/code&gt; attribute instead of the &lt;code&gt;class&lt;/code&gt; attribute; the same principle applies. You want something special to happen when the user clicks on one of those buttons.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use &lt;code&gt;querySelectorAll('button.special')&lt;/code&gt; to get a list of all the right elements,&lt;/li&gt;
&lt;li&gt;Loop through the list, and&lt;/li&gt;
&lt;li&gt;Attach &lt;code&gt;addEventListener('click')&lt;/code&gt; to each element.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That’s fine for a while. But if you’ve got a lot of special buttons, you’ve now got a lot of event listeners. You might be asking the browser to do a lot of work.&lt;/p&gt;

&lt;p&gt;There’s another complication. The code you’ve written runs once, when the page loads. Suppose the contents of the page have changed in the meantime. Maybe elements are swapped in and out using &lt;a href="https://bulletproofajax.com/"&gt;Ajax&lt;/a&gt;. If a new special button shows up on the page, it won’t have an event handler attached to it.&lt;/p&gt;

&lt;p&gt;You can switch things around. Instead of adding lots of event handlers to lots of elements, you can add one event handler to the root element. Then figure out whether the element that just got clicked is special or not.&lt;/p&gt;

&lt;p&gt;That’s where &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/closest"&gt;&lt;code&gt;closest&lt;/code&gt;&lt;/a&gt; comes in. It makes this kind of event handling pretty straightforward.&lt;/p&gt;

&lt;p&gt;To start with, attach the event listener to the document:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;document.addEventListener('click', doSomethingSpecial, false);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That function &lt;code&gt;doSomethingSpecial&lt;/code&gt; will be executed whenever the user clicks on anything. Meanwhile, if the contents of the document are updated via Ajax, no problem!&lt;/p&gt;

&lt;p&gt;Use the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/closest"&gt;&lt;code&gt;closest&lt;/code&gt;&lt;/a&gt; method in combination with the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Event/target"&gt;&lt;code&gt;target&lt;/code&gt;&lt;/a&gt; property of the event to figure out whether that click was something you’re interested in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function doSomethingSpecial(event) {
  if (event.target.closest('button.special')) {
    // do something
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There you go. Like &lt;code&gt;querySelectorAll&lt;/code&gt;, the &lt;code&gt;closest&lt;/code&gt; method takes a CSS selector—&lt;a href="https://css-tricks.com/now-ever-might-not-need-jquery/"&gt;thanks again, jQuery&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Oh, and if you want to reduce the nesting inside that function, you can reverse the logic and &lt;code&gt;return&lt;/code&gt; early like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function doSomethingSpecial(event) {
  if (!event.target.closest('button.special')) return;
  // do something
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There’s a similar method to &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/closest"&gt;&lt;code&gt;closest&lt;/code&gt;&lt;/a&gt; called &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/matches"&gt;&lt;code&gt;matches&lt;/code&gt;&lt;/a&gt;. But that will only work if the user clicks &lt;em&gt;directly&lt;/em&gt; on the element you’re interested in. If the element is nested within other elements, &lt;code&gt;matches&lt;/code&gt; might not work, but &lt;code&gt;closest&lt;/code&gt; will.&lt;/p&gt;

&lt;p&gt;Like &lt;a href="https://mastodon.social/@Meyerweb/111219441257570897"&gt;Eric said&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Very&lt;/em&gt; nice.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>dom</category>
      <category>closest</category>
      <category>methods</category>
      <category>domscripting</category>
    </item>
    <item>
      <title>Making the Patterns Day website</title>
      <dc:creator>Jeremy Keith</dc:creator>
      <pubDate>Tue, 10 Oct 2023 11:33:28 +0000</pubDate>
      <link>https://dev.to/adactio/making-the-patterns-day-website-5d6b</link>
      <guid>https://dev.to/adactio/making-the-patterns-day-website-5d6b</guid>
      <description>&lt;p&gt;I had a lot of fun making &lt;a href="https://patternsday.com/"&gt;the website for Patterns Day&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you’re interested in the tech stack, here’s what I used:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;HTML&lt;/li&gt;
&lt;li&gt;CSS&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Actually, technically it’s all HTML because the styles are inside a &lt;code&gt;style&lt;/code&gt; element rather than a separate style sheet, but you know what I mean. Also, there is technically some JavaScript but all it does is register &lt;a href="https://patternsday.com/serviceworker.js"&gt;a service worker&lt;/a&gt; that takes care of caching and &lt;a href="https://abookapart.com/products/going-offline"&gt;going offline&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I didn’t use any build tools. There was no pipeline. There is no &lt;code&gt;node_modules&lt;/code&gt; folder filling up my hard drive. Nothing was automated. The website was hand-crafted &lt;a href="https://web.archive.org/web/20140311001421/http://frankchimero.com/talks/the-long-hard-stupid-way/transcript"&gt;the long hard stupid way&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I started with the content. I wrote out the words and marked them up with the most appropriate HTML elements.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6vKVQKLt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://adactio.com/images/patternsday2024/patternsday1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6vKVQKLt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://adactio.com/images/patternsday2024/patternsday1.png" alt="A screenshot of an unstyled web page for Patterns Day." width="622" height="720"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Time to layer on the presentation.&lt;/p&gt;

&lt;p&gt;For the design, I turned to &lt;a href="https://clearleft.com/about/team/michelle-winchester"&gt;Michelle&lt;/a&gt; for help. I gave her a brief, describing the vibe of the conference, and asked her to come up with an appropriate visual language.&lt;/p&gt;

&lt;p&gt;Crucially, I asked her &lt;em&gt;not&lt;/em&gt; to design a website. Instead I asked her to think about other places where this design language might be used: a poster, social media, anything but a website.&lt;/p&gt;

&lt;p&gt;Partly I was doing this for my own benefit. If you give me a pixel-perfect design for a web page and tell me to code it up, either I won’t do it or I won’t enjoy it. I just don’t get any motivation out of that kind of direct one-to-one translation.&lt;/p&gt;

&lt;p&gt;But give me guardrails, give me constraints, give me boundary conditions, and off I go!&lt;/p&gt;

&lt;p&gt;Michelle was very gracious in dealing with such a finicky client as myself (“Can you try this other direction?”, “Hmm… I think I preferred the first one after all!”) She delivered a colour palette, a type scale, typeface choices, and some wonderful tiling patterns …it is Patterns Day after all!&lt;/p&gt;

&lt;p&gt;With just a few extra lines of CSS, the basic typography was in place.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--01g2_732--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://adactio.com/images/patternsday2024/patternsday2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--01g2_732--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://adactio.com/images/patternsday2024/patternsday2.png" alt="A screenshot of the web page for Patterns Day with web fonts applied." width="622" height="720"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I started layering on the colours. Even though this was a one-page site, I still made liberal use of custom properties in the CSS. It just &lt;em&gt;feels&lt;/em&gt; good to be able to update one value and see the results, well …cascade.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_oXF5UmV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://adactio.com/images/patternsday2024/patternsday3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_oXF5UmV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://adactio.com/images/patternsday2024/patternsday3.png" alt="A screenshot of the web page for Patterns Day with colours added." width="622" height="720"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I had a lot of fun with the tiling background images. SVG was the perfect format for these. And because the tiles were so small in file size, I just inlined them straight into the CSS.&lt;/p&gt;

&lt;p&gt;By this point, I felt like I was truly designing in the browser. Adjusting spacing, playing around with layout, and all that squishy stuff. Some of the best results came from happy accidents—the way that certain elements behaved at certain screen sizes would lead me into little experiments that yielded interesting results.&lt;/p&gt;

&lt;p&gt;I’m not sure it’s possible to engineer that kind of serendipity in Figma. Figma was the perfect tool for exploring ideas around the visual vocabulary, and for handing over design decisions around colour, typography, and texture. But when it comes to how the content is going to behave on the World Wide Web, nothing beats a browser for fidelity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xVg5ZZqo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://adactio.com/images/patternsday2024/patternsday4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xVg5ZZqo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://adactio.com/images/patternsday2024/patternsday4.png" alt="A screenshot of the web page for Patterns Day with some changes applied." width="622" height="720"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By this point I was really sweating the details, like getting the logo just right and adjusting the type scale for different screen sizes. Needless to say, &lt;a href="https://utopia.fyi/"&gt;Utopia&lt;/a&gt; was a godsend for that.&lt;/p&gt;

&lt;p&gt;I could’ve kept tinkering but the diminishing returns were a sign that it was time to put this out into the world.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--l-hC9JU9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://adactio.com/images/patternsday2024/patternsday5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--l-hC9JU9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://adactio.com/images/patternsday2024/patternsday5.png" alt="A screenshot of the web page for Patterns Day with the logo in place." width="622" height="720"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It felt really good to work on a web page like this. It felt like I was getting my hands into the soil of the web. I don’t think it’s an accident that &lt;a href="https://adactio.com/notes/20525"&gt;the result turned out to be &lt;em&gt;very&lt;/em&gt; performant&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Getting hands-on like this stops me from getting rusty. And honestly, working with CSS these days is a joy. There’s such power to be had from using &lt;code&gt;var()&lt;/code&gt; in combination with functions like &lt;code&gt;calc()&lt;/code&gt; and &lt;code&gt;clamp()&lt;/code&gt;. Layout is a breeze with &lt;code&gt;flexbox&lt;/code&gt; and &lt;code&gt;grid&lt;/code&gt;. Browser differences are practically non-existent. We’ve never had it so good.&lt;/p&gt;

&lt;p&gt;Here’s something I noticed about my relationship to CSS; my brain has finally made the switch to &lt;a href="https://adactio.com/journal/18640"&gt;logical properties&lt;/a&gt;. Now if I’m looking at some CSS and I see &lt;code&gt;left&lt;/code&gt;, &lt;code&gt;right&lt;/code&gt;, &lt;code&gt;top&lt;/code&gt;, or &lt;code&gt;bottom&lt;/code&gt;, it looks like a bug to me. Those directional properties feel loaded with assumptions whereas logical properties feel much more like working with the grain of the web.&lt;/p&gt;

</description>
      <category>patternsday</category>
      <category>website</category>
      <category>frontend</category>
      <category>development</category>
    </item>
  </channel>
</rss>
