<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Alexander Lehner – Oida, is des org!</title><description>Web Development Blog with focus on Accessibility.</description><link>https://www.oidaisdes.org/</link><language>en-us</language><item><title>Enhance Dialogs with the closedby Attribute</title><link>https://www.oidaisdes.org/blog/dialog-closedby-attribute</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/dialog-closedby-attribute</guid><description>Easily add light dismiss behavior or prevent accidental closing via the Escape key.</description><pubDate>Sat, 28 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The native &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt;  HTML element is a thing of beauty. It enables you to easily
create accessible, modal dialogs that work well for all users. And it has been
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/dialog&quot;&gt;supported by all modern browsers since 2022&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But it gets even better: The new &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;closedby&lt;/code&gt;  attribute allows you to define which user
actions will close the dialog. You can add light dismiss behavior, or go the other way: e.g., prevent
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;ESC&lt;/code&gt;  key from closing the dialog.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-miguel-a-padrinan-speech-bubbles.0fhF8W61_Z1NUbqr.webp&quot; srcset=&quot;/_astro/pexels-miguel-a-padrinan-speech-bubbles.0fhF8W61_Z1FNTgA.webp 640w, /_astro/pexels-miguel-a-padrinan-speech-bubbles.0fhF8W61_jlO9b.webp 750w, /_astro/pexels-miguel-a-padrinan-speech-bubbles.0fhF8W61_1CSVna.webp 828w, /_astro/pexels-miguel-a-padrinan-speech-bubbles.0fhF8W61_Z1Y8AMY.webp 1080w, /_astro/pexels-miguel-a-padrinan-speech-bubbles.0fhF8W61_foBIH.webp 1280w, /_astro/pexels-miguel-a-padrinan-speech-bubbles.0fhF8W61_Z1NUbqr.webp 1600w&quot; alt=&quot;Two white speech bubbles on a pink background.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1064&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Miguel Á. Padriñán / pexels.com&lt;/p&gt;
&lt;p&gt;We’ll take a look at the technical specification and some use cases for the new attribute.&lt;/p&gt;
&lt;h2 id=&quot;how-it-works&quot;&gt;How it works&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://html.spec.whatwg.org/multipage/interactive-elements.html#the-dialog-element&quot;&gt;HTML specification&lt;/a&gt;
defines &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;closedby&lt;/code&gt;  as an enumerated attribute with the following keywords:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;any&lt;/code&gt;  – Close requests or clicks outside close the dialog.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;closerequest&lt;/code&gt;  – Close requests close the dialog.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;none&lt;/code&gt;  – No user actions automatically close the dialog.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you don’t set the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;closedby&lt;/code&gt;  attribute on a modal dialog, then it behaves as if the
value was &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;closerequest&lt;/code&gt; . This means, pressing the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;ESC&lt;/code&gt;  key on
desktop platforms, or a “back” or “dismiss” gesture on mobile platforms, will close the dialog.&lt;/p&gt;
&lt;h2 id=&quot;use-cases&quot;&gt;Use Cases&lt;/h2&gt;
&lt;h3 id=&quot;light-dismiss-for-informational-dialogs&quot;&gt;Light Dismiss for Informational Dialogs&lt;/h3&gt;
&lt;p&gt;Some dialogs only present information. The user isn’t expected to make a decision or fill in a form.
In my opinion, this is a perfect use case for adding light dismiss behavior: The dialog should close when the
user clicks or taps outside it.&lt;/p&gt;
&lt;p&gt;Before we had the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;closedby&lt;/code&gt;  attribute, you needed additional JavaScript code to implement
light dismiss. See my article &lt;a href=&quot;/blog/native-dialog-element/&quot;&gt;“Why you should use the Native Dialog Element”&lt;/a&gt; for
an example. Lucky for us, now we only need the following HTML code:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dialog&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; closedby&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;any&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;    &amp;lt;!-- content --&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dialog&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Awesome! 🥳&lt;/p&gt;
&lt;h3 id=&quot;prevent-accidental-closing&quot;&gt;Prevent Accidental Closing&lt;/h3&gt;
&lt;p&gt;Dialogs are a great way to encapsulate workflows like, e.g., the data entry via a form.
You can also handle the onboarding process for your web application with a dialog.&lt;/p&gt;
&lt;p&gt;In all these cases, you’ll want to prevent the user from accidentally closing the dialog, e.g., via
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;ESC&lt;/code&gt;  key. They would lose the data they had already filled in the form, or not be
able to access the onboarding dialog again.&lt;/p&gt;
&lt;p&gt;Therefore, you should set &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;closedby=“none”&lt;/code&gt;  on the dialog. Now the user can only close
the dialog via a developer-specified mechanism, like a close button. Here’s an example:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dialog&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;mydialog&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; closedby&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;none&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;    &amp;lt;!-- content --&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; commandfor&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;mydialog&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; command&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;close&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        Continue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dialog&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Maybe you’re wondering about the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;command&lt;/code&gt;  and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;commandfor&lt;/code&gt; 
attributes on the close button. They’re part of a new web feature called
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Invoker_Commands_API&quot;&gt;Invoker Commands API&lt;/a&gt;. You don’t have
to use them in your dialogs. But I like their simplicity and elegance, so I wanted to include them in my
code example. 😉&lt;/p&gt;
&lt;h2 id=&quot;browser-support&quot;&gt;Browser Support&lt;/h2&gt;
&lt;p&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;closedby&lt;/code&gt;  attribute is already &lt;a href=&quot;https://caniuse.com/wf-dialog-closedby&quot;&gt;supported by Firefox, Chrome and Edge&lt;/a&gt;.
Thanks to &lt;a href=&quot;https://wpt.fyi/interop-2026&quot;&gt;Interop 2026&lt;/a&gt;, Safari/WebKit should catch up until the end of the year.&lt;/p&gt;
&lt;h2 id=&quot;useful-resources&quot;&gt;Useful Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/dialog#closedby&quot;&gt;The closedby attribute (MDN)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/accessibility-engineering-web-platform/&quot;&gt;“Accessibility Engineering — Let the Web Platform do the Work”&lt;/a&gt; (section: “The dialog element: Always on top”)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/native-dialog-and-popover/&quot;&gt;“Native Dialogs and the Popover API — What you need to know”&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>accessibility</category><category>css</category><category>dialog</category><category>html</category><category>keyboard</category><category>sreenreader</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_speech_bubbles.jpg" length="0" type="image/jpeg"/></item><item><title>Best Practices for CSS Scope in Angular Applications</title><link>https://www.oidaisdes.org/blog/css-scope-angular-best-practices</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/css-scope-angular-best-practices</guid><description>Learn how to write efficient donut scopes and easily override 3rd party components.</description><pubDate>Tue, 24 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The new &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@scope&lt;/code&gt;  CSS at-rule has been supported by all major browsers since December 2025. This
awesome new feature makes it super easy to scope styles to specific DOM subtrees, like the content of a component.&lt;/p&gt;
&lt;p&gt;At work, I mostly implement web applications with the Angular framework. The last few months, I started to ditch
&lt;a href=&quot;https://angular.dev/guide/components/styling#style-scoping&quot;&gt;Angular’s default view encapsulation&lt;/a&gt; and use the native CSS
feature instead. Now I’d like to share my learnings and some best practices with you.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-aditya-aiyar-donuts.C_8mSwN1_hmyth.webp&quot; srcset=&quot;/_astro/pexels-aditya-aiyar-donuts.C_8mSwN1_ZhaK5p.webp 640w, /_astro/pexels-aditya-aiyar-donuts.C_8mSwN1_Z1nOj3D.webp 750w, /_astro/pexels-aditya-aiyar-donuts.C_8mSwN1_Z1Wushy.webp 828w, /_astro/pexels-aditya-aiyar-donuts.C_8mSwN1_Z2hJy79.webp 1080w, /_astro/pexels-aditya-aiyar-donuts.C_8mSwN1_Z1NuK6e.webp 1280w, /_astro/pexels-aditya-aiyar-donuts.C_8mSwN1_hmyth.webp 1600w&quot; alt=&quot;A box with several donuts in different colors.&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1067&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Aditya Aiyar / pexels.com&lt;/p&gt;
&lt;p&gt;If you’re unfamiliar with CSS scope, then read my article
&lt;a href=&quot;/blog/css-scope-view-encapsulation/&quot;&gt;“Will the CSS Scope Feature replace Angular’s View Encapsulation?”&lt;/a&gt; first. It explains the
basics of the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@scope&lt;/code&gt;  CSS at-rule and how to use it in Angular.&lt;/p&gt;
&lt;h2 id=&quot;demo-project-css-scope-sandbox&quot;&gt;Demo Project: CSS Scope Sandbox&lt;/h2&gt;
&lt;p&gt;I’ve created a &lt;a href=&quot;https://github.com/alexlehner86/angular-css-scope-sandbox&quot;&gt;project with two Angular applications&lt;/a&gt; that display
the same content. The only difference is: The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;app-without-css-scope&lt;/code&gt;  uses the standard view encapsulation
provided by the Angular framework. On the other hand, the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;app-with-css-scope&lt;/code&gt;  disables this feature and
uses the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@scope&lt;/code&gt;  CSS at-rule instead.&lt;/p&gt;
&lt;p&gt;Here’s the deployed application with CSS scope. Go ahead and inspect it using your browser’s developer tools:&lt;/p&gt;
&lt;iframe src=&quot;https://alexlehner86.github.io/angular-css-scope-sandbox/&quot; title=&quot;Demo: App with CSS @scope&quot; loading=&quot;lazy&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;I love how clean and tidy the DOM looks. It’s way easier to understand the page structure and inspect the styles of an element.&lt;/p&gt;
&lt;p&gt;The CSS selectors you see in the browser’s dev tools match those you defined in your source code. No more weird
additions of custom attributes like &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;_ngcontent-xxx&lt;/code&gt; .&lt;/p&gt;
&lt;p&gt;So, what are the best practices for CSS scope that I’d recommend?&lt;/p&gt;
&lt;h2 id=&quot;best-practice-1-use-efficient-donut-scopes&quot;&gt;Best Practice 1: Use efficient Donut Scopes&lt;/h2&gt;
&lt;p&gt;First of all, we need to disable view encapsulation for each of our components. Here’s an example from my demo:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;Component&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    selector:&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;#39;app-beer-item-list&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    encapsulation:&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; ViewEncapsulation&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;None&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; BeerItemList&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now the CSS selectors won’t be extended with custom attributes and the component styles are applied globally.
Next, we need to use the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@scope&lt;/code&gt;  at-rule instead to encapsulate the styles.&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@scope&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; (app-beer-item-list) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;    :scope&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        display&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;grid&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This defines the component’s container element &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;app-beer-item-list&lt;/code&gt;  as
the &lt;span class=&quot;c-italic&quot;&gt;scoping root&lt;/span&gt;  which determines the upper boundary of the subtree we want to target.&lt;/p&gt;
&lt;p&gt;But what about the content rendered by the child components in the template? The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;BeerItemList&lt;/code&gt; 
component includes the child component &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;app-beer-item-details&amp;gt;&lt;/code&gt;  in its template. We don’t want
the parent component’s styles to affect the content of its children.&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@scope&lt;/code&gt;  at-rule allows us to define a &lt;span class=&quot;c-italic&quot;&gt;scoping limit&lt;/span&gt;  which determines the
lower boundary. This type of scoping  – with an upper and lower boundary – is called a
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@scope#scope_roots_and_scope_limits&quot;&gt;donut scope&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@scope&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; (app-beer-item-list) to (app-beer-item-details &amp;gt; *) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;    :scope&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        display&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;grid&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;    app-beer-item-details&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        background&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;--canvas-bg-color&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This scope includes the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;app-beer-item-details&amp;gt;&lt;/code&gt;  container element but excludes the
content of the child component.&lt;/p&gt;
&lt;p&gt;What happens when you’re styling a component that includes several child components in its template? For example, the
app component in my demo includes the child components &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;AppFooter&lt;/code&gt; , &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;AppHeader&lt;/code&gt; 
and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;BeerItemList&lt;/code&gt; . You would have to define each child component as a scoping limit, which would
get annoying really fast.&lt;/p&gt;
&lt;p&gt;To make using CSS scope easier, I’ve created the custom directive &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;CustomNgHostDirective&lt;/code&gt; . The
directive adds the custom attribute &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;data-ng-host&lt;/code&gt;  to a component’s container HTML element. Simply
apply the directive to a component with the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;hostDirectives&lt;/code&gt;  property:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;Component&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    selector:&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;#39;app-beer-item-details&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    encapsulation:&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; ViewEncapsulation&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;None&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    hostDirectives:&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;CustomNgHostDirective&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; BeerItemDetails&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can use the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;data-ng-host&lt;/code&gt;  attribute for an efficient definition of the lower boundary
of an &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@scope&lt;/code&gt;  at-rule. For example:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@scope&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; (app-beer-item-list) to ([data-ng-host] &amp;gt; *) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;    :scope&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        display&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;grid&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;    app-beer-item-details&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        background&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;--canvas-bg-color&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;best-practice-2-go-deep-without-ng-deep&quot;&gt;Best Practice 2: Go deep without &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;::ng-deep&lt;/code&gt; &lt;/h2&gt;
&lt;p&gt;When using Angular’s view encapsulation, component styles normally apply only to the HTML in the component’s own template.
You can use the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;::ng-deep&lt;/code&gt;  pseudo-class to disable view encapsulation for a specific rule.
But this pseudo-class has been &lt;a href=&quot;https://angular.dev/guide/components/styling#ng-deep&quot;&gt;deprecated&lt;/a&gt; for
a while and you’re not supposed to use it anymore.&lt;/p&gt;
&lt;p&gt;With CSS scope, you’re in control again! You can define the scope in a way that lets you safely override, e.g., the inner
styles of a 3rd party library.&lt;/p&gt;
&lt;p&gt;For example: Let’s say you’re using an &lt;a href=&quot;https://material.angular.dev/components/table/overview&quot;&gt;Angular Material table&lt;/a&gt;
to display tabular data. You’re mostly happy with the design but would like to tweak the background colors a bit.
Here’s what your component’s styles could look like:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@scope&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; (app-fancy-table) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;    table&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;mat-table&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        thead tr {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            background-color&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;lightblue&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;best-practice-3-define-shared-styles-as-global-css-classes&quot;&gt;Best Practice 3: Define shared styles as Global CSS Classes&lt;/h2&gt;
&lt;p&gt;Not all your styles have to be defined as scoped styles in the CSS file of a component. You’ll want to put shared styles
in global files, e.g. in your &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;src/styles&lt;/code&gt;  folder, and provide them for the whole application.&lt;/p&gt;
&lt;p&gt;I personally prefer to create SCSS files with general styles for each type of content or element.
For example: &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;_details.scss&lt;/code&gt; , &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;_forms.scss&lt;/code&gt;  and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;_table.scss&lt;/code&gt; .
They contain styles for specific HTML selectors like, e.g., &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;details&lt;/code&gt; , as well as global CSS
classes like, e.g., &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;.default-expansion-panel&lt;/code&gt; .&lt;/p&gt;
&lt;p&gt;To make it easy for components to override these general styles, if necessary, I put them in a dedicated cascade layer:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@use&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; &amp;quot;sass:meta&amp;quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@layer&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; reset, general, components;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@layer&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; general {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;    @include&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; meta.load-css(&amp;quot;base/details&amp;quot;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;    @include&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; meta.load-css(&amp;quot;base/forms&amp;quot;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;    @include&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; meta.load-css(&amp;quot;base/table&amp;quot;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Learn more about cascade layers in my article &lt;a href=&quot;/blog/cascade-layers-in-angular/&quot;&gt;“Using CSS Cascade Layers in Angular”&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As an alternative, you might prefer to use SCSS features like &lt;a href=&quot;https://sass-lang.com/documentation/at-rules/extend/&quot;&gt;placeholders&lt;/a&gt;
or &lt;a href=&quot;https://sass-lang.com/documentation/at-rules/mixin/&quot;&gt;mixins&lt;/a&gt; to create reusable styles. I can confirm that including a mixin
with &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@include&lt;/code&gt;  also works within the context of the native &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@scope&lt;/code&gt;  at-rule.&lt;/p&gt;
&lt;p&gt;Unfortunately, using an SCSS placeholder with &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@extend&lt;/code&gt;  didn’t work for me in the context of CSS scope.
The SCSS preprocessor apparently doesn’t account for the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@scope&lt;/code&gt;  at-rule yet, resulting in unscoped
styles. At least that was the case for me with Angular 21. Maybe it will be fixed in the future.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;As I’ve shown you, it’s pretty easy to switch off Angular’s view encapsulation and define component styles inside
a &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@scope&lt;/code&gt;  at-rule. The generated HTML and CSS code has better readability and is far
easier to debug.&lt;/p&gt;
&lt;p&gt;Or in other words: Angular’s view encapsulation is dead! Long live CSS scope! 🤩&lt;/p&gt;</content:encoded><category>angular</category><category>css</category><category>encapsulation</category><category>scope</category><category>styling</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_donuts2.jpg" length="0" type="image/jpeg"/></item><item><title>Using the Temporal API in Angular without including a Polyfill</title><link>https://www.oidaisdes.org/blog/use-temporal-api-in-angular</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/use-temporal-api-in-angular</guid><description>Add type definitions for Temporal without blowing up the bundle size of your app.</description><pubDate>Sat, 31 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Temporal&lt;/code&gt;  API is gaining momentum! Chrome and Edge 144 recently shipped with Temporal support.
They finally caught up to Firefox, the first browser to enable the Temporal API by default in May 2025. The
&lt;a href=&quot;https://bugs.webkit.org/show_bug.cgi?id=223166&quot;&gt;implementation in WebKit/Safari&lt;/a&gt; is also making progress.&lt;/p&gt;
&lt;p&gt;Well, I can’t wait to finally ditch the horrible &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Date&lt;/code&gt;  object and embrace modern date and time management
with &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Temporal&lt;/code&gt; , including built-in time zone and calendar representation. Don’t know what I’m talking about?
Then read my article &lt;a href=&quot;/blog/temporal-api-first-look/&quot;&gt;“Date and Time Management with the Temporal API”&lt;/a&gt; first!&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-lukaszmartenka-wrist-watch.Iaq1nJzD_1HQlQm.webp&quot; srcset=&quot;/_astro/pexels-lukaszmartenka-wrist-watch.Iaq1nJzD_1IcPmA.webp 640w, /_astro/pexels-lukaszmartenka-wrist-watch.Iaq1nJzD_Z1czQrn.webp 750w, /_astro/pexels-lukaszmartenka-wrist-watch.Iaq1nJzD_1PsU9K.webp 828w, /_astro/pexels-lukaszmartenka-wrist-watch.Iaq1nJzD_1B0Sav.webp 1080w, /_astro/pexels-lukaszmartenka-wrist-watch.Iaq1nJzD_Z1ABr3y.webp 1280w, /_astro/pexels-lukaszmartenka-wrist-watch.Iaq1nJzD_iorYw.webp 1668w, /_astro/pexels-lukaszmartenka-wrist-watch.Iaq1nJzD_2pN7Cv.webp 2048w, /_astro/pexels-lukaszmartenka-wrist-watch.Iaq1nJzD_Zj0KAo.webp 2560w, /_astro/pexels-lukaszmartenka-wrist-watch.Iaq1nJzD_1HQlQm.webp 5544w&quot; alt=&quot;A closeup of an analogue wrist watch.&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 5544px) 5544px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;5544&quot; height=&quot;3696&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Łukasz Martenka / pexels.com&lt;/p&gt;
&lt;p&gt;In my current project at work, I’m developing a new web application with &lt;a href=&quot;https://angular.dev/&quot;&gt;Angular 21&lt;/a&gt; that doesn’t have to
support Safari. The perfect opportunity to go all in with the Temporal API.&lt;/p&gt;
&lt;p&gt;The only problem is: The &lt;a href=&quot;https://github.com/tc39/proposal-temporal&quot;&gt;Temporal proposal&lt;/a&gt; is still at stage 3 in the TC39 proposal process.
Therefore, the current TypeScript version doesn’t include types for Temporal objects yet. When I try to use &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Temporal&lt;/code&gt; 
in my Angular application, the TypeScript compiler will refuse and say: &lt;span class=&quot;c-italic&quot;&gt;“Cannot find name ‘Temporal’.”&lt;/span&gt;  😢&lt;/p&gt;
&lt;p&gt;After some tinkering, I found a solution for the problem: I’ll show you how to
add type definitions for Temporal without blowing up the bundle size of your app. 🤩&lt;/p&gt;
&lt;h2 id=&quot;step-1-install-the-temporal-polyfill&quot;&gt;Step 1: Install the Temporal Polyfill&lt;/h2&gt;
&lt;p&gt;Install the &lt;a href=&quot;https://www.npmjs.com/package/@js-temporal/polyfill&quot;&gt;@js-temporal/polyfill&lt;/a&gt; package as a dev dependency for your
Angular project:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; --save-dev&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; @js-temporal/polyfill&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The documentation recommends to import the polyfill in the following way:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;Temporal&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;#39;@js-temporal/polyfill&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Don’t do this! The polyfill actually includes the JavaScript code for all objects and methods of the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Temporal&lt;/code&gt;  API.
This import would increase the bundle size of your application by &lt;strong&gt;around 150 kB&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Here’s what you do instead.&lt;/p&gt;
&lt;h2 id=&quot;step-2-declare-a-global-temporal-object&quot;&gt;Step 2: Declare a global &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Temporal&lt;/code&gt;  object&lt;/h2&gt;
&lt;p&gt;Create a new file &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;src/types/temporal.d.ts&lt;/code&gt;  in your repository and include the following code:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#C586C0&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;Temporal&lt;/span&gt;&lt;span style=&quot;color:#C586C0&quot;&gt; as&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; TemporalType&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;quot;@js-temporal/polyfill&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;declare&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; global&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; Temporal&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; typeof&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; TemporalType&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We only import the type definitions for the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Temporal&lt;/code&gt;  namespace from the polyfill package. Then we declare a
global constant named &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Temporal&lt;/code&gt;  and assign it the imported type. This way we teach TypeScript that the Temporal
namespace exists and that it includes several objects like &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Instant&lt;/code&gt; , &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Now&lt;/code&gt; 
and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;ZonedDateTime&lt;/code&gt; .&lt;/p&gt;
&lt;p&gt;Now, you can use all features of the Temporal API in any &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;.ts&lt;/code&gt;  file without an additional import. For example:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; zdt&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; Temporal&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;ZonedDateTime&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;2026-01-30T12:34:56-04:00[America/New_York]&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;During runtime of the web application, the actual global &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Temporal&lt;/code&gt;  object of the browser will be used.&lt;/p&gt;
&lt;h2 id=&quot;step-3-using-types-from-the-temporal-namespace&quot;&gt;Step 3: Using types from the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Temporal&lt;/code&gt;  namespace&lt;/h2&gt;
&lt;p&gt;The last piece of the puzzle: If you want to use Temporal types for variables or class properties, you need to import and use the
type definitions the following way:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#C586C0&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;Temporal&lt;/span&gt;&lt;span style=&quot;color:#C586C0&quot;&gt; as&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; TemporalType&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;quot;@js-temporal/polyfill&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;interface&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; MyInterface&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    property&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; TemporalType&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;ZonedDateTime&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;demo-application&quot;&gt;Demo application&lt;/h2&gt;
&lt;p&gt;I’ve created a simple &lt;a href=&quot;https://github.com/alexlehner86/temporal-api-angular-app&quot;&gt;demo app&lt;/a&gt; with Angular 21 following the steps above.
It includes a time zone picker and a simple date calculator. Both were super easy to implement, thanks to the
elegant and powerful &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal&quot;&gt;Temporal API&lt;/a&gt;.&lt;/p&gt;
&lt;iframe src=&quot;https://alexlehner86.github.io/temporal-api-angular-app/&quot; title=&quot;Demo: Temporal API Angular App&quot; loading=&quot;lazy&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;If you just started working on a new Angular application, then give it a go! &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Temporal&lt;/code&gt;  is simply awesome and
you’ll love using it. 😉&lt;/p&gt;</content:encoded><category>angular</category><category>calendar</category><category>date</category><category>javascript</category><category>temporal</category><category>typescript</category><category>time</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_wrist_watch.jpg" length="0" type="image/jpeg"/></item><item><title>My First Steps as an Astronaut</title><link>https://www.oidaisdes.org/blog/astro-framework-first-steps</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/astro-framework-first-steps</guid><description>The advantages of using the web framework Astro to manage my web dev blog.</description><pubDate>Mon, 12 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’m officially an astronaut! Well, not an actual astronaut who journeys into space. Rather, a happy user of the
web framework &lt;a href=&quot;https://astro.build/&quot;&gt;Astro&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Many in the Astro community affectionately refer to themselves as &lt;span class=&quot;c-italic&quot;&gt;“Astronauts”&lt;/span&gt;  – playing on the
framework’s name. And now I’m one of them! After four years of managing my web blog with &lt;a href=&quot;https://www.gatsbyjs.com/&quot;&gt;Gatsby&lt;/a&gt;,
it was time to move on and switch to a different framework.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-cottonbro-astronaut.GBSE7KHP_qC0rG.webp&quot; srcset=&quot;/_astro/pexels-cottonbro-astronaut.GBSE7KHP_27B4Ch.webp 640w, /_astro/pexels-cottonbro-astronaut.GBSE7KHP_10WvE3.webp 750w, /_astro/pexels-cottonbro-astronaut.GBSE7KHP_rhmq8.webp 828w, /_astro/pexels-cottonbro-astronaut.GBSE7KHP_16LbC7.webp 1080w, /_astro/pexels-cottonbro-astronaut.GBSE7KHP_Oc7Lp.webp 1280w, /_astro/pexels-cottonbro-astronaut.GBSE7KHP_Z1IDPsT.webp 1668w, /_astro/pexels-cottonbro-astronaut.GBSE7KHP_Z1jrNz8.webp 2048w, /_astro/pexels-cottonbro-astronaut.GBSE7KHP_8I1j3.webp 2560w, /_astro/pexels-cottonbro-astronaut.GBSE7KHP_qC0rG.webp 3500w&quot; alt=&quot;A man in a white leather coat, wearing an astronaut like helmet.&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 3500px) 3500px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;3500&quot; height=&quot;2333&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © cottonbro / pexels.com&lt;/p&gt;
&lt;p&gt;I’ll explain why I left Gatsby behind and what I like about Astro.&lt;/p&gt;
&lt;h2 id=&quot;why-i-dropped-gatsby&quot;&gt;Why I dropped Gatsby&lt;/h2&gt;
&lt;p&gt;I must admit I’ve been lazy! Back in January 2022 I set up my web blog with Gatsby 4. After I was happy with the configuration
and everything worked well enough, I never really touched the setup again. I also never updated the project’s dependencies.&lt;/p&gt;
&lt;p&gt;The setup simply worked. So, I preferred to spend my time experimenting with new web features and writing blog posts.&lt;/p&gt;
&lt;p&gt;Now, four years later, I had to admit to myself that my setup had become completely outdated! The Gatsby CLI felt clunky
and slow, and building my web blog for production took up to 15 minutes. Unacceptable!&lt;/p&gt;
&lt;p&gt;My first thought was to update to the latest Gatsby version and optimize my setup. But then I came across GitHub issues
like &lt;a href=&quot;https://github.com/gatsbyjs/gatsby/discussions/39062&quot;&gt;“Is GatsbyJS Officially Dead?”&lt;/a&gt; and
&lt;a href=&quot;https://github.com/gatsbyjs/gatsby/issues/38696&quot;&gt;“Is Gatsby discontinued?”&lt;/a&gt;. Apparently, the framework is no longer
actively developed and has become hopelessly outdated.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;c-italic&quot;&gt;“Well, time to move on!”,&lt;/span&gt;  was my conclusion. After some research on various frameworks for static site
generation, I settled on Astro as an ideal fit for me.&lt;/p&gt;
&lt;h2 id=&quot;what-i-like-about-astro&quot;&gt;What I like about Astro&lt;/h2&gt;
&lt;p&gt;I’ve now finished setting up my web blog with Astro, maintaining the same basic features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A bilingual website in English and German.&lt;/li&gt;
&lt;li&gt;A homepage with a short introduction and a list of recent blog posts.&lt;/li&gt;
&lt;li&gt;An about page with more information about me and the website.&lt;/li&gt;
&lt;li&gt;A blog archive with links to all my published posts.&lt;/li&gt;
&lt;li&gt;Blog posts created from Markdown files.&lt;/li&gt;
&lt;li&gt;Automatic creation of RSS files.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Switching to Astro went pretty smoothly, thanks to its familiar component structure and built-in support for Markdown. Here’s
what I especially like about Astro:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The framework offers very detailed &lt;a href=&quot;https://docs.astro.build/en/getting-started/&quot;&gt;documentation&lt;/a&gt;, including an interactive
tutorial for building a blog. Perfect for my use case! They even have several migration guides, e.g.,
&lt;a href=&quot;https://docs.astro.build/en/guides/migrate-to-astro/from-gatsby/&quot;&gt;Migrating from Gatsby&lt;/a&gt;, that explain key differences.&lt;/li&gt;
&lt;li&gt;Astro components (&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;.astro&lt;/code&gt;  files) make it easy to implement basic building blocks for different pages.
If you’re familiar with JSX, you’ll feel right at home! 🤩&lt;/li&gt;
&lt;li&gt;Per default, Astro renders your web pages to fast, static HTML. If you need interactive JavaScript logic, you define
a &lt;a href=&quot;https://docs.astro.build/en/concepts/islands/&quot;&gt;client island&lt;/a&gt;: an interactive UI component that is hydrated separately
from the rest of the page. I used this concept to add a filter component to my blog archive page. Worked like a charm!&lt;/li&gt;
&lt;li&gt;There’s a vibrant community and a ton of plugins.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-future-looks-bright&quot;&gt;The Future Looks Bright&lt;/h2&gt;
&lt;p&gt;I’m very happy with my choice of framework. Astro is simply delightful to work with. And I have a feeling that I’ve only scratched
the surface of what’s possible.&lt;/p&gt;
&lt;p&gt;Hopefully, Astro stays open source and alive for a long time. I don’t want to switch framework again in a few years. 😝&lt;/p&gt;</content:encoded><category>astro</category><category>dx</category><category>framework</category><category>tools</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_astronaut.jpg" length="0" type="image/jpeg"/></item><item><title>Flexible Menu Animation with Anchored Container Queries</title><link>https://www.oidaisdes.org/blog/anchored-container-queries</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/anchored-container-queries</guid><description>We can query the currently active fallback position and apply different styles with CSS only.</description><pubDate>Sun, 23 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Chrome has just released a new version 143 with
&lt;a href=&quot;https://chromestatus.com/feature/5177580990496768&quot;&gt;support for CSS anchored fallback container queries&lt;/a&gt;. These queries
enable us to style an anchored element’s descendants based on its current position relative to the anchor. That’s pretty cool! 🤩&lt;/p&gt;
&lt;p&gt;A few months ago, I published an &lt;a href=&quot;/blog/accessible-popover-menu/&quot;&gt;article on building an accessible custom menu&lt;/a&gt;
with the Popover API and CSS Anchor Positioning. In the article, I complained that I had to resort to JavaScript to make the
scaling animation work for different positions of the menu panel relative to the menu button.&lt;/p&gt;
&lt;p&gt;Well, not anymore! I’ll show you how to define the menu panel’s animation with CSS only.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-snapwire-hands-with-anchors.BcKsEZ2y_Z1Ut9bf.webp&quot; srcset=&quot;/_astro/pexels-snapwire-hands-with-anchors.BcKsEZ2y_Z2spwf9.webp 640w, /_astro/pexels-snapwire-hands-with-anchors.BcKsEZ2y_Z6XciE.webp 750w, /_astro/pexels-snapwire-hands-with-anchors.BcKsEZ2y_8aydQ.webp 828w, /_astro/pexels-snapwire-hands-with-anchors.BcKsEZ2y_ZagQQO.webp 1080w, /_astro/pexels-snapwire-hands-with-anchors.BcKsEZ2y_1gXFmH.webp 1280w, /_astro/pexels-snapwire-hands-with-anchors.BcKsEZ2y_Z1Ut9bf.webp 1600w&quot; alt=&quot;Two hands with intertwined index fingers. Each index finger has a black anchor tatoo.&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1060&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Snapwire / pexels.com&lt;/p&gt;
&lt;h2 id=&quot;the-basics-of-anchored-container-queries&quot;&gt;The Basics of Anchored Container Queries&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.w3.org/TR/css-anchor-position-2/&quot;&gt;CSS Anchor Positioning Module Level 2&lt;/a&gt; document introduces the
new &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;anchored&lt;/code&gt;  value for the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;container-type&lt;/code&gt;  property. It states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Establishes a query container for container queries, allowing for descendants of an anchor positioned element to be styled
based on certain features of the anchoring. (Currently, limited to which of the position-try-fallbacks are applied, if any.)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In our use case, we have a custom menu panel that is anchored to its menu button. When we
apply &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;container-type: anchored&lt;/code&gt;  to the menu panel, we turn it into a query container that’s aware of its
anchor positioning state.&lt;/p&gt;
&lt;p&gt;This allows us to adapt the menu panel’s scaling effect to its current position, using the new
at-rule &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@container anchored(fallback: …)&lt;/code&gt; . For example: When the panel is placed at the top and left
of the button, we let it grow out of the bottom right corner.&lt;/p&gt;
&lt;p&gt;Before we take an in-depth look at the HTML and CSS code, check out the final demo of the custom menu.&lt;/p&gt;
&lt;h2 id=&quot;demo-accessible-menu-with-css-only-animation&quot;&gt;Demo: Accessible Menu with CSS only animation&lt;/h2&gt;
&lt;p&gt;I’ve created a new &lt;a href=&quot;https://codepen.io/alexlehner86/pen/KwzveJz&quot;&gt;CodePen demo&lt;/a&gt; that includes the same menu element four times,
placed roughly at the four corners of the screen. This way, you can easily test how the animation of the menu panel takes
into account the position relative to the menu button:&lt;/p&gt;
&lt;iframe title=&quot;Menu Anchor Positioning (with Container Query)&quot; src=&quot;https://codepen.io/alexlehner86/embed/KwzveJz?default-tab=result&quot; loading=&quot;lazy&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/alexlehner86/pen/KwzveJz&quot;&gt;
Menu Anchor Positioning (with Container Query)&lt;/a&gt; by Alexander Lehner (&lt;a href=&quot;https://codepen.io/alexlehner86&quot;&gt;@alexlehner86&lt;/a&gt;)
on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;&lt;/iframe&gt;
&lt;p&gt;If your browser doesn’t support anchored container queries, the menu panel will simply fade in. I’ll show you the details
of implementing the scaling effect as a progressive enhancement.&lt;/p&gt;
&lt;h2 id=&quot;how-to-use-anchored-container-queries-for-flexible-animations&quot;&gt;How to use Anchored Container Queries for Flexible Animations&lt;/h2&gt;
&lt;p&gt;I’m not going to repeat all the details of the accessible custom menu I built. Make sure to read my article
&lt;a href=&quot;/blog/accessible-popover-menu/&quot;&gt;“Let’s build an Accessible Menu with Modern Web Features”&lt;/a&gt; first before you continue.&lt;/p&gt;
&lt;h3 id=&quot;step-1-the-basic-html-structure&quot;&gt;Step 1: The basic HTML structure&lt;/h3&gt;
&lt;p&gt;To make the anchored container query work, we need to slightly adapt the HTML structure of our custom menu. I tried to
apply the change to the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;div[role=“menu”]&lt;/code&gt;  element itself, but it had no effect. Why is that?&lt;/p&gt;
&lt;p&gt;The official specification states that the container query only allows for &lt;strong&gt;descendants&lt;/strong&gt;
of an anchor positioned element to be styled. This means, we need an additional inner container:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu-btn-1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu-btn&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; aria-label&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;More options&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; popovertarget&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu-content-1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;button&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;/* icon */&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu-content-1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; aria-labelledby&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu-btn-1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; popover&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu-inner-box&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menuitem&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;button&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menuitem&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;button&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menuitem&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;button&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;.menu-inner-box&lt;/code&gt;  element is a descendant of our menu panel. Therefore, we can change
its &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;transform-origin&lt;/code&gt;  depending on the menu panel’s anchor positioning state.&lt;/p&gt;
&lt;h3 id=&quot;step-2-menu-panel-animation&quot;&gt;Step 2: Menu Panel Animation&lt;/h3&gt;
&lt;p&gt;The panel should fade in and grow in size when it is opened. As the transition applies to a popover that changes
from &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;display: none&lt;/code&gt;  to &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;display: flex&lt;/code&gt; , we also need to transition
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;overlay&lt;/code&gt;  and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;display&lt;/code&gt;  properties. Here’s the basic setup for the panel:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;    /* General animation and end of fade-out */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    opacity&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transition-property&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: opacity, &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;overlay&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, display;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    transition-behavior: allow-discrete;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transition-duration&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;100ms&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transition-timing-function&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;linear&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The scaling animation is defined separately for the inner container. As the menu panel’s default position is to the bottom
and right of the menu button, we set &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;transform-origin: top left&lt;/code&gt;  for the scaling effect:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt; .menu-inner-box&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transform&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;scale&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transform-origin&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;top&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; left&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transition-property&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: transform;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transition-duration&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;inherit&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transition-timing-function&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;inherit&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We want the fade-in to last 120 milliseconds and use a smooth cubic-bezier timing function. At the end of the transition,
the popover is fully visible and scaled to 100 percent:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;]:&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;popover-open&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;    /* End of fade-in and start of fade-out */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transition-duration&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;120ms&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transition-timing-function&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;cubic-bezier&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.2&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    opacity&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;]:&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;popover-open&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt; .menu-inner-box&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transform&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;scale&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As the menu panel switches from a hidden to a visible state, there are no computed values that the transition can use as
a starting point. Therefore, we use &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@starting-style&lt;/code&gt;  to set the starting opacity to 0 and the initial
scale to 80 percent:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;/* Start of fade-in */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@starting-style&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;    div&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;]:&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;popover-open&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        opacity&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;    div&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;]:&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;popover-open&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt; .menu-inner-box&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        transform&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;scale&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.8&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this setup, the scaling animation works for the default placement of the menu panel. Next, we’ll use anchored container
queries to adapt the animation to different positions.&lt;/p&gt;
&lt;h3 id=&quot;step-3-position-fallbacks&quot;&gt;Step 3: Position Fallbacks&lt;/h3&gt;
&lt;p&gt;Our menu button is implicitly defined as the anchor element of the menu panel. Therefore, we simply define the default
placement of the menu panel and several fallbacks:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    position&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;fixed&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    position-area: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; span-end;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    position-try-fallbacks: flip-block, flip-inline, flip-block flip-inline;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When the anchored element (the menu panel) overflows its containing block, the browser will automatically try the list of
alternative positions defined by the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;position-try-fallbacks&lt;/code&gt;  property. It will use the first alternative
that doesn’t overflow the containing block or viewport.&lt;/p&gt;
&lt;p&gt;How can we detect which fallback position was picked by the browser? First, we turn the menu panel into a query container
for its anchor position:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    container-type&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: anchored;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can define anchored queries to check the fallback and adapt the animation accordingly. Here’s an example:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@container&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; anchored(fallback: flip-block) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;    div&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt; .menu-inner-box&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        transform-origin&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;bottom&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; left&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When the menu panel’s position is flipped in the block axis (moved to the top), then this at-rule will take effect and make
the panel appear to grow outwards from the menu button. Awesome! 😍&lt;/p&gt;
&lt;p&gt;You can find the rest of the necessary container queries in the CSS code of my
&lt;a href=&quot;https://codepen.io/alexlehner86/pen/KwzveJz&quot;&gt;CodePen demo&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;step-4-progressive-enhancement&quot;&gt;Step 4: Progressive Enhancement&lt;/h3&gt;
&lt;p&gt;Last but not least, we don’t want the animation of the menu panel to break on browsers that don’t support anchored container
queries yet. Using the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@supports&lt;/code&gt;  at-rule, we only define the scaling effect for the inner container
as well as the container queries if the browser supports it:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@supports&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;container-type&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: anchored) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;    div&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        container-type&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: anchored;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;    /* Styles related to the scaling effect animation */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Progressive enhancement has never been this easy!&lt;/p&gt;
&lt;h2 id=&quot;useful-resources&quot;&gt;Useful Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Anchor_positioning/Using&quot;&gt;Using CSS anchor positioning (MDN)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/position-try-fallbacks&quot;&gt;position-try-fallbacks (MDN)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/blog/anchored-container-queries&quot;&gt;Detect fallback positions with anchored container queries from Chrome 143&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>accessibility</category><category>animation</category><category>css</category><category>html</category><category>menu</category><category>popover</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_hands_with_anchors.jpg" length="0" type="image/jpeg"/></item><item><title>Let&apos;s Play Accordion with the HTML details element</title><link>https://www.oidaisdes.org/blog/lets-play-accordion</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/lets-play-accordion</guid><description>An in-depth look at the new capabilities of the native disclosure element.</description><pubDate>Sat, 27 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Managing content on a website can be challenging. You don’t want to overwhelm your users with too much information at once.
One helpful strategy is to place content in sections with show/hide functionality. A typical example would be an FAQ page with
a list of expandable questions and answers.&lt;/p&gt;
&lt;p&gt;We can use the native &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;details&amp;gt;&lt;/code&gt;  HTML element to create such a disclosure widget. The element has
been around for many years, but it used to be tricky to style and animate. Thanks to &lt;a href=&quot;https://wpt.fyi/interop-2025&quot;&gt;Interop 2025&lt;/a&gt;,
browsers have greatly improved their implementations of the element and added new features.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-jefferson-lucena-accordion-player.Bn-TfkHc_Z2sD12B.webp&quot; srcset=&quot;/_astro/pexels-jefferson-lucena-accordion-player.Bn-TfkHc_Z1Sefrw.webp 640w, /_astro/pexels-jefferson-lucena-accordion-player.Bn-TfkHc_1YhjI0.webp 750w, /_astro/pexels-jefferson-lucena-accordion-player.Bn-TfkHc_ZOpVTx.webp 828w, /_astro/pexels-jefferson-lucena-accordion-player.Bn-TfkHc_Z1C553K.webp 1080w, /_astro/pexels-jefferson-lucena-accordion-player.Bn-TfkHc_1H4RTi.webp 1280w, /_astro/pexels-jefferson-lucena-accordion-player.Bn-TfkHc_Z2sD12B.webp 1600w&quot; alt=&quot;An older man sitting on a chair in front of a doorway, playing accordion.&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1067&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Jefferson Lucena / pexels.com&lt;/p&gt;
&lt;p&gt;I’ll quickly go over the basics of the native HTML element. Then we’ll take a look at the new shiny features. 🤩&lt;/p&gt;
&lt;h2 id=&quot;the-details-html-element&quot;&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;details&amp;gt;&lt;/code&gt;  HTML element&lt;/h2&gt;
&lt;p&gt;The native &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/details&quot;&gt;details element&lt;/a&gt; creates a disclosure
widget, also called an expansion panel. The information placed inside the element is visible only when the widget is toggled into
an open state. We use the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;summary&amp;gt;&lt;/code&gt;  HTML element to provide a label for the widget. Here’s an
example:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;details&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;An interesting question?&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;A fascinating answer!&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;details&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With just a few lines of code we get a fully accessible disclosure widget. It communicates its name, role and current status to
assistive technologies and is fully operable with a keyboard.&lt;/p&gt;
&lt;h2 id=&quot;new-features&quot;&gt;New Features&lt;/h2&gt;
&lt;h3 id=&quot;exclusive-accordions-with-the-name-attribute&quot;&gt;Exclusive Accordions with the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;name&lt;/code&gt;  attribute&lt;/h3&gt;
&lt;p&gt;An accordion component is a common UI pattern found on many websites. It consists of several disclosure widgets that individually
can be expanded and collapsed.&lt;/p&gt;
&lt;p&gt;A variation of the accordion pattern is the &lt;span class=&quot;c-italic&quot;&gt;exclusive accordion&lt;/span&gt; , in which only one section can be open at
the same time. Use the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;name&lt;/code&gt;  attribute to turn a list of &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;details&amp;gt;&lt;/code&gt;  elements
into an exclusive accordion. Take a look at this code snippet from my &lt;a href=&quot;https://codepen.io/alexlehner86/pen/gbbJLZd&quot;&gt;CodePen demo&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;details&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;faq&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;What is the Doctor&amp;#39;s real name?&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;I&amp;#39;ll never tell!&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;details&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;details&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;faq&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Who are the Daleks?&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;The Daleks are...&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;details&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now the individual disclosure widgets are linked. When you open one of the sections in the accordion, the browser will
automatically close all other sections. Try it yourself:&lt;/p&gt;
&lt;iframe title=&quot;FAQ Accordion with Details Element&quot; src=&quot;https://codepen.io/alexlehner86/embed/gbbJLZd?default-tab=result&quot; loading=&quot;lazy&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/alexlehner86/pen/gbbJLZd&quot;&gt;
FAQ Accordion with Details Element&lt;/a&gt; by Alexander Lehner (&lt;a href=&quot;https://codepen.io/alexlehner86&quot;&gt;@alexlehner86&lt;/a&gt;)
on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;&lt;/iframe&gt;
&lt;h3 id=&quot;content-styling-with-details-content&quot;&gt;Content Styling with &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;::details-content&lt;/code&gt; &lt;/h3&gt;
&lt;p&gt;You can easily style the expandable content of the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;details&amp;gt;&lt;/code&gt;  element using the
new &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;::details-content&lt;/code&gt;  CSS pseudo-element. Here’s an example:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;details&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;details-content&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    color&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;rgb&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;54&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;69&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;79&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    line-height&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1.3&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    padding-inline&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.5rem&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Furthermore, we can use the pseudo-element to animate the opening and closing of our disclosure widget. Our goal is to smoothly
transition the content from zero height to its full height. To pull this off, we depend on the still
experimental &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;interpolate-size&lt;/code&gt;  CSS property, which is
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/interpolate-size#browser_compatibility&quot;&gt;only supported in Chromium browsers at the moment&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But don’t worry! We can implement the animation as a progressive enhancement. Using the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@supports&lt;/code&gt;  at-rule,
we only apply the animation when the browser supports it:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@supports&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; (interpolate-size: allow-keywords) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;    details&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        interpolate-size: allow-keywords;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        &amp;amp;::details-content {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;            height: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            overflow-y&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;clip&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            transition&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;                height &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.35s&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; ease&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;                content-visibility &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.35s&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; ease&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; allow-discrete;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;    details&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;open&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;]::&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;details-content&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        height&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;auto&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I know, there’s a lot going on in the CSS code above. I’ll explain it step-by-step:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;By default, browsers don’t support animations and transitions involving an intrinsic size value like &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;auto&lt;/code&gt; .
We enable this behavior by setting &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;interpolate-size: allow-keywords&lt;/code&gt; .&lt;/li&gt;
&lt;li&gt;We set the initial height of the content to zero (&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;height: 0&lt;/code&gt; ) and clip any overflowing content.&lt;/li&gt;
&lt;li&gt;Using the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;transition&lt;/code&gt;  shorthand, we define the animation of the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;height&lt;/code&gt;  property.
We also need to include the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;content-visibility&lt;/code&gt;  property, which is automatically set by the browser when the
details element is expanded or collapsed.
See &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/transition-behavior&quot;&gt;transition-behavior&lt;/a&gt; for more information.&lt;/li&gt;
&lt;li&gt;At last, we set &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;height: auto&lt;/code&gt;  for the content when the details element is in the open state.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Open my &lt;a href=&quot;https://codepen.io/alexlehner86/pen/gbbJLZd&quot;&gt;CodePen demo&lt;/a&gt; in Chrome or Edge to see the smooth animations for yourself. 😎&lt;/p&gt;
&lt;h3 id=&quot;custom-indicator-for-openclosed-state&quot;&gt;Custom Indicator for open/closed state&lt;/h3&gt;
&lt;p&gt;Browsers typically present the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;details&amp;gt;&lt;/code&gt;  element with a small triangle that rotates to indicate
open/closed state. This indicator will appear differently across platforms and browsers.&lt;/p&gt;
&lt;p&gt;To replace the default triangle with a custom indicator, we need to override the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;display: list-item&lt;/code&gt; 
value of the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;summary&amp;gt;&lt;/code&gt;  element. I use flexbox as this supports my desired layout. But you could also
set &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;display: block&lt;/code&gt; , for example.&lt;/p&gt;
&lt;p&gt;In addition, we also need to hide the pseudo-elements for the default triangle. This
includes &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;::-webkit-details-marker&lt;/code&gt; , which is used in the Safari browser:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;details&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt; summary&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    display&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;flex&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    align-items&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;center&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    justify-content&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;space-between&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    gap&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1rem&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    &amp;amp;::marker,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    &amp;amp;::-webkit-details-marker {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        display: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;none&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we define our custom indicator. I want to display an arrow icon that points downwards when the disclosure widget is closed.
Thanks to modern CSS, we don’t need any images or icon fonts. We can simply draw the shape using the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;::after&lt;/code&gt; 
pseudo-element and the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;clip-path&lt;/code&gt;  CSS property.&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;details&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt; summary::after&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    --shape-chevron-width&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1rem&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    --s&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;calc&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;--shape-chevron-width&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    content&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    aspect-ratio&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;7&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    background&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;currentColor&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    clip-path&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;polygon&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;--s&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;50%&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 100%&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;100%&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;--s&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;100%&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;50%&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;100%&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;--s&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;)));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    flex-shrink&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    width&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;--shape-chevron-width&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I adapted a code example from the website &lt;a href=&quot;https://css-shape.com/chevron/&quot;&gt;CSS Shape&lt;/a&gt;. It offers tons of code snippets for pure
CSS shapes made with a single-element and modern CSS. You should definitely check it out! 🥰&lt;/p&gt;
&lt;p&gt;Finally, we want the arrow icon to point upwards when the disclosure widget is open. Of course, the transition should be animated.
Here’s the code:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;details&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    summary::after {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        rotate: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0deg&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        transition&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: rotate &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.35s&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; ease&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    &amp;amp;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;open&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;summary::after&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        rotate&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;-180deg&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span lang=&quot;fr&quot;&gt;Et voilà!&lt;/span&gt; We’ve replaced the default triangle with a custom arrow icon that looks the same on all
platforms and browsers. Here’s the final result:&lt;/p&gt;
&lt;iframe title=&quot;Accordion with Custom Arrows&quot; src=&quot;https://codepen.io/alexlehner86/embed/KwVPYOw?default-tab=result&quot; loading=&quot;lazy&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/alexlehner86/pen/KwVPYOw&quot;&gt;
Accordion with Custom Arrows&lt;/a&gt; by Alexander Lehner (&lt;a href=&quot;https://codepen.io/alexlehner86&quot;&gt;@alexlehner86&lt;/a&gt;)
on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;&lt;/iframe&gt;
&lt;h3 id=&quot;flexbox-and-grid-layouts&quot;&gt;Flexbox and Grid Layouts&lt;/h3&gt;
&lt;p&gt;Historically it wasn’t possible to change the display type of the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;details&amp;gt;&lt;/code&gt;  element. This restriction
has now been relaxed in all major browsers (e.g., &lt;a href=&quot;https://www.firefox.com/en-US/firefox/143.0/releasenotes/&quot;&gt;Firefox 143&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;That means, it’s finally possible to use grid or flex layouts on the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;details&amp;gt;&lt;/code&gt;  element. Check out the
article &lt;a href=&quot;https://developer.chrome.com/blog/styling-details&quot;&gt;“More options for styling &amp;lt;details&amp;gt;”&lt;/a&gt; on the Chrome Developer blog.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;details&amp;gt;&lt;/code&gt;  and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;summary&amp;gt;&lt;/code&gt;  elements are awesome! Thanks to the new
features we can easily create disclosure widgets and even exclusive accordions with custom styling and animations.&lt;/p&gt;
&lt;p&gt;This means: One more type of content we can build with native web features. No need for UI library components and their annoying
tendency for breaking changes. I love the (native) web! ❤️&lt;/p&gt;</content:encoded><category>accessibility</category><category>accordion</category><category>css</category><category>disclosure</category><category>html</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_accordion_player.jpg" length="0" type="image/jpeg"/></item><item><title>How to Create an Accessible Table with Clickable Rows</title><link>https://www.oidaisdes.org/blog/table-with-clickable-rows</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/table-with-clickable-rows</guid><description>Extend the reach of your buttons to support keyboard and screen reader users.</description><pubDate>Mon, 25 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Tables on websites usually display static information in rows and columns. But what if you want to make the rows clickable,
e.g., to show more information about the thing that the row is about? Your first thought might be to put
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element/click_event&quot;&gt;click event handlers&lt;/a&gt; on the
table rows (&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;tr&amp;gt;&lt;/code&gt; ) to make them clickable. But you really shouldn’t!&lt;/p&gt;
&lt;p&gt;A table row with a click event handler doesn’t magically turn into an accessible control. You won’t be able to focus the row
using a keyboard, let alone trigger the click event using the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;ENTER&lt;/code&gt;  key. The purpose of the click event
handler would be unclear to a screen reader user. So what should we do?&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-kampus-finger-tap-smartphone.B_6wqSgx_2KOwy.webp&quot; srcset=&quot;/_astro/pexels-kampus-finger-tap-smartphone.B_6wqSgx_2cBSYI.webp 640w, /_astro/pexels-kampus-finger-tap-smartphone.B_6wqSgx_Z2u04mc.webp 750w, /_astro/pexels-kampus-finger-tap-smartphone.B_6wqSgx_wFhz6.webp 828w, /_astro/pexels-kampus-finger-tap-smartphone.B_6wqSgx_1jOAML.webp 1080w, /_astro/pexels-kampus-finger-tap-smartphone.B_6wqSgx_2jFsiu.webp 1280w, /_astro/pexels-kampus-finger-tap-smartphone.B_6wqSgx_2KOwy.webp 1600w&quot; alt=&quot;A woman touches the screen of a smartphone with her index finger.&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1068&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Kampus Production / pexels.com&lt;/p&gt;
&lt;p&gt;To create an accessible table with clickable rows, we simply take a &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;button&amp;gt;&lt;/code&gt;  element and
extend its reach to cover the whole row. My solution is inspired by Adrian Roselli’s article
&lt;a href=&quot;https://adrianroselli.com/2023/11/dont-turn-a-table-into-an-aria-grid-just-for-a-clickable-row.html&quot;&gt;“Don’t Turn a Table into an ARIA Grid Just for a Clickable Row”&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;demo-table-with-clickable-rows&quot;&gt;Demo: Table with Clickable Rows&lt;/h2&gt;
&lt;p&gt;I’ve created a &lt;a href=&quot;https://codepen.io/alexlehner86/pen/VYvdLZZ&quot;&gt;CodePen demo&lt;/a&gt; that lists several &lt;a href=&quot;https://en.wikipedia.org/wiki/Studio_Ghibli&quot;&gt;Studio Ghibli&lt;/a&gt;
movies in a tabular format. Each row can be clicked to open a dialog with more information about the movie:&lt;/p&gt;
&lt;iframe title=&quot;Table with Clickable Row&quot; src=&quot;https://codepen.io/alexlehner86/embed/VYvdLZZ?default-tab=result&quot; loading=&quot;lazy&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/alexlehner86/pen/VYvdLZZ&quot;&gt;
Table with Clickable Row&lt;/a&gt; by Alexander Lehner (&lt;a href=&quot;https://codepen.io/alexlehner86&quot;&gt;@alexlehner86&lt;/a&gt;)
on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;&lt;/iframe&gt;
&lt;h2 id=&quot;building-the-accessible-table&quot;&gt;Building the Accessible Table&lt;/h2&gt;
&lt;h3 id=&quot;the-ideal-solution&quot;&gt;The Ideal Solution&lt;/h3&gt;
&lt;p&gt;We add a &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;button&amp;gt;&lt;/code&gt;  element in the last table cell of each row. The button’s accessible name
(&lt;span class=&quot;c-italic&quot;&gt;“More Information”&lt;/span&gt; ) together with the row heading (the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;th&amp;gt;&lt;/code&gt;  element in
the row) inform screen reader users about the purpose of the control:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;tr&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;th&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Spirited Away&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;th&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;td&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;2001&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;td&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;td&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;2h 4m&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;td&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;td&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;info-btn-1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; aria-label&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;More Information&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;button&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;            &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;/* icon */&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;td&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;tr&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The button is keyboard operable by default. All we need to do is to visually convey that the whole table row is focused.
We can use the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;:focus-within&lt;/code&gt;  CSS pseudo-class:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;table&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt; tbody&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt; tr&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    &amp;amp;:focus-within, &amp;amp;:hover {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        outline: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.188rem&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; solid&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; black&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        outline-offset&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;-0.313rem&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;    button:focus&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        outline&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;none&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This way, the table row is highlighted on hover or when the button within the row receives focus.&lt;/p&gt;
&lt;p&gt;Finally, we want to trigger the button when the user clicks on the table row. To achieve this, we use
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;::after&lt;/code&gt;  pseudo-element together with the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;inset&lt;/code&gt;  CSS property:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;table&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt; tbody&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt; tr&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    position&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;relative&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    button::after {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;        content&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        position&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;absolute&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        inset&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The pseudo-element is absolutely positioned relative to its parent &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;tr&amp;gt;&lt;/code&gt;  element and covers the
whole table row thanks to &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;inset: 0&lt;/code&gt; . Now, a click on the table row will count as a click on the button
within. Awesome! 🤩&lt;/p&gt;
&lt;p&gt;There’s only one problem: &lt;a href=&quot;https://bugs.webkit.org/show_bug.cgi?id=240961&quot;&gt;It doesn’t work in Safari&lt;/a&gt; (at the moment).
The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;position: relative&lt;/code&gt;  definition for the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;tr&amp;gt;&lt;/code&gt;  element is simply ignored. 🤬&lt;/p&gt;
&lt;h3 id=&quot;the-safari-supported-version&quot;&gt;The Safari Supported Version&lt;/h3&gt;
&lt;p&gt;As long as the WebKit bug isn’t fixed, we need a workaround. I’ve created an
&lt;a href=&quot;https://codepen.io/alexlehner86/pen/NPGzQbK&quot;&gt;alternative CodePen demo&lt;/a&gt; that also works in Safari:&lt;/p&gt;
&lt;iframe title=&quot;Table with Clickable Row (Safari Support)&quot; src=&quot;https://codepen.io/alexlehner86/embed/NPGzQbK?default-tab=result&quot; loading=&quot;lazy&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/alexlehner86/pen/NPGzQbK&quot;&gt;
Table with Clickable Row (Safari Support)&lt;/a&gt; by Alexander Lehner (&lt;a href=&quot;https://codepen.io/alexlehner86&quot;&gt;@alexlehner86&lt;/a&gt;)
on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;&lt;/iframe&gt;
&lt;p&gt;The solution is a bit hacky, but it works. Instead of using the table row as the relative anchor, we position the pseudo-element
relative to its parent &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;td&amp;gt;&lt;/code&gt;  element. Take a look:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;table&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    overflow&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;clip&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;table&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt; tbody&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt; tr&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    td:has(button) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        position&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;relative&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;    button::after&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        content&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        position&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;absolute&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        inset&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        left&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;auto&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        width&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;100vw&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We revert the pseudo-element’s &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;left&lt;/code&gt;  property to &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;auto&lt;/code&gt;  and set its width
to 100% of the viewport width. In addition, we set &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;overflow: clip&lt;/code&gt;  on the table to limit the reach of
each button to the actual width of the table row.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;As you can see, creating an accessible table with clickable rows isn’t that hard. Always keep in mind that not all of your users
use a mouse or a touch device. Always test with keyboard and screen readers as well. 😉&lt;/p&gt;</content:encoded><category>accessibility</category><category>css</category><category>html</category><category>keyboard</category><category>table</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_finger_tap_smartphone.jpg" length="0" type="image/jpeg"/></item><item><title>Let&apos;s build an Accessible Menu with Modern Web Features</title><link>https://www.oidaisdes.org/blog/accessible-popover-menu</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/accessible-popover-menu</guid><description>A step by step guide, using the Popover API and CSS Anchor Positioning.</description><pubDate>Mon, 14 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;We’re all familiar with menu elements on websites. A &lt;a href=&quot;https://www.w3.org/WAI/ARIA/apg/patterns/menubar/&quot;&gt;menu&lt;/a&gt; is a widget that
offers a list of choices to the user, such as a set of actions. Such menus behave like native operating system menus and should
not be confused with &lt;a href=&quot;/blog/accessible-navigation-menu/&quot;&gt;navigation menus&lt;/a&gt; that are commonly placed in the page header.&lt;/p&gt;
&lt;p&gt;Unfortunately, the existing &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;menu&amp;gt;&lt;/code&gt;  element doesn’t behave as expected. There are
&lt;a href=&quot;https://open-ui.org/components/menu.explainer/&quot;&gt;plans to adapt the native element&lt;/a&gt;, but in the meantime we have to create our own
custom menu. We could use a menu component from a UI library. Which represents another dependency for your project, and possibly
breaking changes in the future. I’d rather not.&lt;/p&gt;
&lt;p&gt;But there’s good news! Thanks to new web features like the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Popover_API&quot;&gt;Popover API&lt;/a&gt;
and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_anchor_positioning&quot;&gt;CSS Anchor Positioning&lt;/a&gt;, creating your own
custom menu element has become a lot easier. Let’s build an accessible menu together!&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-zachary-debottis-skateboarder-jump.s-LpGV1f_14UB5b.webp&quot; srcset=&quot;/_astro/pexels-zachary-debottis-skateboarder-jump.s-LpGV1f_utH8m.webp 640w, /_astro/pexels-zachary-debottis-skateboarder-jump.s-LpGV1f_Z2tTReH.webp 750w, /_astro/pexels-zachary-debottis-skateboarder-jump.s-LpGV1f_1uFmq9.webp 828w, /_astro/pexels-zachary-debottis-skateboarder-jump.s-LpGV1f_Z1WCApy.webp 1080w, /_astro/pexels-zachary-debottis-skateboarder-jump.s-LpGV1f_ZTSXNp.webp 1280w, /_astro/pexels-zachary-debottis-skateboarder-jump.s-LpGV1f_14UB5b.webp 1600w&quot; alt=&quot;A skateboarder in mid air jump, like a menu panel popping up.&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1007&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Zachary DeBottis / pexels.com&lt;/p&gt;
&lt;h2 id=&quot;what-we-want-to-achieve&quot;&gt;What we want to achieve&lt;/h2&gt;
&lt;p&gt;Our custom menu should meet the following requirements:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The menu is fully accessible, meaning:
&lt;ul&gt;
&lt;li&gt;It conveys its role and status to assistive technologies like screen readers.&lt;/li&gt;
&lt;li&gt;It supports keyboard operation and has a visible focus indicator.&lt;/li&gt;
&lt;li&gt;The text and graphical elements have sufficient color contrast.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Inside the menu panel, the user can activate one of several menu items. For the sake of
simplicity, we don’t support nested menus (maybe I’ll look into this in the future).&lt;/li&gt;
&lt;li&gt;The menu panel opens next to the trigger button and stays attached on scrolling.&lt;/li&gt;
&lt;li&gt;The opening and closing of the menu panel is smoothly animated.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I’ll show you how to achieve this step by step. But first, take a look at the result.&lt;/p&gt;
&lt;h2 id=&quot;demo-accessible-menu&quot;&gt;Demo: Accessible Menu&lt;/h2&gt;
&lt;p&gt;I’ve created a &lt;a href=&quot;https://codepen.io/alexlehner86/pen/pvJKxQR&quot;&gt;CodePen demo&lt;/a&gt; that includes the same menu element four times,
placed roughly at the four corners of the screen. This way, you can easily test how the placement of the menu panel takes
into account the available space:&lt;/p&gt;
&lt;iframe title=&quot;Menu Anchor Positioning Testcase&quot; src=&quot;https://codepen.io/alexlehner86/embed/pvJKxQR?default-tab=result&quot; loading=&quot;lazy&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/alexlehner86/pen/pvJKxQR&quot;&gt;
Menu Anchor Positioning Testcase&lt;/a&gt; by Alexander Lehner (&lt;a href=&quot;https://codepen.io/alexlehner86&quot;&gt;@alexlehner86&lt;/a&gt;)
on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;&lt;/iframe&gt;
&lt;h2 id=&quot;building-the-menu-element-step-by-step&quot;&gt;Building the Menu Element step by step&lt;/h2&gt;
&lt;h3 id=&quot;step-1-the-basic-html-structure&quot;&gt;Step 1: The basic HTML structure&lt;/h3&gt;
&lt;p&gt;We define an icon &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;button&lt;/code&gt;  with an &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;aria-label&lt;/code&gt;  to communicate its purpose
to screen reader users. Next to it, we place a &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;div&lt;/code&gt;  container with several buttons inside it, creating
the menu panel. The attributes &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;role=“menu”&lt;/code&gt;  on the container and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;role=“menuitem”&lt;/code&gt; 
on each button convey the appropriate roles to assistive technologies:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu-btn-1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu-btn&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; aria-label&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;More options&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;button&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;/* icon */&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; aria-labelledby&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu-btn-1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menuitem&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;button&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;More information&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menuitem&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;button&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Share&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menuitem&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;button&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Download the file&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With CSS, we style our menu button to have a good target size and proper color contrast. We turn the menu panel into a
flex container that arranges its menu items in a column. Here’s an excerpt:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;button.menu-btn&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    color&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;white&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    background-color&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;#00514c&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;    /* other styling */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    display&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;flex&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    flex-direction&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;column&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    margin&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.25rem&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;    /* other styling */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, what have we got? An icon button with an always visible list of buttons next to it. Now we build upon this
foundation to create our accessible menu.&lt;/p&gt;
&lt;h3 id=&quot;step-2-using-popover-api-for-the-menu-panel&quot;&gt;Step 2: Using Popover API for the menu panel&lt;/h3&gt;
&lt;p&gt;Next, we add the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;popover&lt;/code&gt;  attribute to our menu panel. This causes the menu panel to be hidden on
page load. When the popover is shown, it is put into the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/Top_layer&quot;&gt;top layer&lt;/a&gt;
so it will sit on top of all other page content.&lt;/p&gt;
&lt;p&gt;Now, we want our menu button to control when the menu panel is shown or hidden. To create this connection, we assign
an &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;id&lt;/code&gt;  to the popover element and set the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;popovertarget&lt;/code&gt;  attribute with the
ID value on the menu button. Here’s the end result:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; popovertarget&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu-content-1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu-btn-1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu-btn&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; aria-label&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;More options&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;button&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;/* icon */&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; popover&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu-content-1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; aria-labelledby&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu-btn-1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    /* menu items */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These simple steps already provide us with a lot of features: The menu button opens and closes the panel, it communicates its
state to assistive technologies (like &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;aria-expanded&lt;/code&gt;  would), we get light-dismiss and some keyboard
operability. Find out more in the MDN article &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Popover_API/Using&quot;&gt;Using the Popover API&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One important piece of advice on styling popover content: If you want to use a flexbox or grid layout, you should only change
the value of the popover’s &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;display&lt;/code&gt;  property when the popover is open. Otherwise, you would override
its &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;display: none&lt;/code&gt;  value when it is closed, making it always visible. Here’s a code example:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    flex-direction&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;column&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    margin&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.25rem&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;    /* other styling */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    &amp;amp;:popover-open {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        display: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;flex&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-3-panel-placement-with-css-anchor-positioning&quot;&gt;Step 3: Panel placement with CSS Anchor Positioning&lt;/h3&gt;
&lt;p&gt;To establish a visual link between the menu button and its panel, we need to place them next to each other. And we want to ensure
that the panel stays tethered to the menu button, e.g., on scrolling. Historically, this would necessitate the use of a JavaScript
overlay library. How annoying!&lt;/p&gt;
&lt;p&gt;Lucky for us, the new &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_anchor_positioning&quot;&gt;CSS Anchor Positioning&lt;/a&gt; feature
does the job for us. It is currently part of &lt;a href=&quot;https://wpt.fyi/interop-2025&quot;&gt;Interop 2025&lt;/a&gt; and should be supported in all browsers
by the end of the year.&lt;/p&gt;
&lt;p&gt;In general, you need to define an anchor element using the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;anchor-name&lt;/code&gt;  property. Then you would tether
another element to this anchor with the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;position-anchor&lt;/code&gt;  property. In case of popover elements, you don’t
need to do any of this. As the &lt;a href=&quot;https://www.w3.org/TR/css-anchor-position-1/#implicit&quot;&gt;specification&lt;/a&gt; states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Some specifications can define that, in certain circumstances, a particular element is
an &lt;strong&gt;implicit anchor element&lt;/strong&gt; for another element. Implicit anchor elements can be referenced
with the &lt;strong&gt;auto&lt;/strong&gt; keyword in position-anchor.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This applies to a button that serves as a popover control, like our menu button. Which means: We’re good to go! Our menu button is
implicitly defined as the anchor element of the menu panel.&lt;/p&gt;
&lt;p&gt;So where should we place the panel? How about below and to the right of the button? We could achieve this using
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;anchor()&lt;/code&gt;  function for inset properties. But I prefer the more elegant and
straight-forward &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;position-area&lt;/code&gt;  property. Take a look:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    position&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;absolute&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    position-area: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; span-end;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should think of the anchor element and the space around it as a 3x3 grid. The first value we define refers to the block axis,
the second one to the inline axis. So, &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;position-area: end span-end&lt;/code&gt;  means, that we want to place our menu panel
at the end of the block axis (below the button) and to let it span from the center to the end of the inline axis (center to right).&lt;/p&gt;
&lt;p&gt;But what happens when the menu button is placed on the right edge of the screen? Or if the page’s scroll position places the button
at the lower edge of the screen? In both cases, there’s not enough space to display the menu panel with all its options below and
to the right of the menu button.&lt;/p&gt;
&lt;p&gt;We can easily solve this issue with the help of the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;position-try-fallbacks&lt;/code&gt;  property. It allows us to
specify a list of one or more alternative positions. When the element would otherwise overflow its containing block, the browser
will try placing the positioned element in these different fallback positions.&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;position-try-fallbacks&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;flip-block&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;flip-inline&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;flip-block&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; flip-inline&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We basically tell the browser: If there’s not enough space below the menu button, then move the menu panel above the button. Not
enough space to the right? Ok, then flip the inline axis and let the menu panel span the space from the left to the center. And
if neither of these work alone, then do both (&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;flip-block flip-inline&lt;/code&gt; ).&lt;/p&gt;
&lt;h3 id=&quot;step-4-keyboard-interaction-with-javascript&quot;&gt;Step 4: Keyboard Interaction with JavaScript&lt;/h3&gt;
&lt;p&gt;Our custom menu should be fully operable for keyboard users. The &lt;a href=&quot;https://www.w3.org/WAI/ARIA/apg/patterns/menubar/&quot;&gt;ARIA APG Menu Pattern&lt;/a&gt;
defines the following requirements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When a menu opens, keyboard focus is placed on the first item.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Tab&lt;/code&gt;  and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Shift + Tab&lt;/code&gt;  do not move focus among the items in the menu.&lt;/li&gt;
&lt;li&gt;When focus is in a menu, &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Down Arrow&lt;/code&gt;  moves focus to the next item, optionally wrapping from the last
to the first.&lt;/li&gt;
&lt;li&gt;When focus is in a menu, &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Up Arrow&lt;/code&gt;  moves focus to the previous item, optionally wrapping from the first
to the last.&lt;/li&gt;
&lt;li&gt;When focus is on a menuitem in a menu, then &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Tab&lt;/code&gt;  and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Shift + Tab&lt;/code&gt;  move focus
out of the menu, and close all menus and submenus.&lt;/li&gt;
&lt;li&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Enter&lt;/code&gt;  key activates the item and closes the menu.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Escape&lt;/code&gt;  closes the menu that contains focus and returns focus to the menu button.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The last requirement is already taken care of thanks to the Popover API. For the rest, we need to implement some JavaScript code
and adjust our HTML structure. First, we set &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;tabindex=“-1”&lt;/code&gt;  on all menu items, to take them out of the
focus order:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; popover&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu-content-1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; aria-labelledby&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu-btn-1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menuitem&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; tabindex&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;-1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;button&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;More information&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menuitem&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; tabindex&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;-1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;button&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Share&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menuitem&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; tabindex&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;-1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;button&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Download the file&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’ve written a JavaScript class named &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;MenuNavigationHandler&lt;/code&gt;  that encapsulates the required interactivity
of the custom menu element. You simply create a new instance of the class, passing a specific menu element as the parameter.
Here’s an excerpt from the code:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; MenuNavigationHandler&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;    constructor&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;menuEl&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;menuEl&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; menuEl&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;menuBtn&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; document&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;getElementById&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;menuEl&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;getAttribute&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;aria-labelledby&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;menuItems&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; Array&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;menuEl&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;children&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;selectedItem&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;selectedItemIndex&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;        // Handle interaction with menu&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;menuEl&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;addEventListener&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;toggle&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, (&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;onMenuOpen&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;menuEl&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;addEventListener&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;keydown&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, (&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;onMenuKeydown&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;menuEl&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;addEventListener&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;click&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, (&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;onMenuClick&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;    // Private methods&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; menus&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; document&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;#39;div[role=&amp;quot;menu&amp;quot;]&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;menus&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;forEach&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;item&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; MenuNavigationHandler&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;item&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The constructor stores references to the menu button and menu panel. It adds event listeners for the popover toggle event
as well as keydown and click events on the menu panel. You can dig into all the code in my
&lt;a href=&quot;https://codepen.io/alexlehner86/pen/pvJKxQR&quot;&gt;CodePen demo&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;step-5-adding-smooth-animations&quot;&gt;Step 5: Adding Smooth Animations&lt;/h3&gt;
&lt;p&gt;Last but not least, we want the custom menu to look and feel good. We use CSS transitions to animate the opening and closing
of the menu panel.&lt;/p&gt;
&lt;p&gt;The panel should fade in and grow in size when it is opened. As the transition applies to a popover that changes
from &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;display: none&lt;/code&gt;  to &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;display: flex&lt;/code&gt; , we also need to transition
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;overlay&lt;/code&gt;  and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;display&lt;/code&gt;  properties. The basic setup looks like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transition&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: opacity, transform, &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;overlay&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, display;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    transition-behavior: allow-discrete;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We want the fade-in to last 120 milliseconds and use a smooth cubic-bezier timing function. At the end of the transition,
the popover is fully visible and scaled to 100 percent:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;]:&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;popover-open&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;    /* End of fade-in and start of fade-out */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transition-duration&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;120ms&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transition-timing-function&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;cubic-bezier&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.2&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    opacity&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transform&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;scale&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As the menu panel switches from a hidden to a visible state, there are no computed values that the transition can use as
a starting point. Therefore, we use &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@starting-style&lt;/code&gt;  to set the starting opacity to 0 and the initial
scale to 80 percent:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@starting-style&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;    /* Start of fade-in */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;    div&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;]:&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;popover-open&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        opacity&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        transform&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;scale&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.8&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, to define the end values for the fade-out state, we simply leave out the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;:popover-open&lt;/code&gt;  pseudo-class
and define the styles for the menu element in general. We want a snappier, linear animation that only lasts 100 milliseconds:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;    /* End of fade-out */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transition-duration&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;100ms&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transition-timing-function&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;linear&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    opacity&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transform&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;scale&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Alright, the animation looks pretty cool already. We could leave it at that. But I want to achieve one more thing: The menu panel
should appear to be growing out of the menu button. As we’re using the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;transform&lt;/code&gt;  property for the scaling
effect, we simply need to define its origin like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;transform-origin&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: top left;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But there’s a problem! The origin should adapt to the placement of the menu panel next to the menu button. For example, when the
panel opens to the top and left of the button, then we would need to define &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;bottom right&lt;/code&gt;  as the origin.&lt;/p&gt;
&lt;p&gt;Unfortunately, the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;position-try-fallbacks&lt;/code&gt;  we defined don’t affect the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;transform-origin&lt;/code&gt; 
property. I also tried to define custom position options with the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@position-try&lt;/code&gt;  rule. But then I realized
that the specification (and browser implementation) only allows a very limited set of properties. It just didn’t work.&lt;/p&gt;
&lt;p&gt;There’s a note in the &lt;a href=&quot;https://www.w3.org/TR/css-anchor-position-1/#fallback-rule&quot;&gt;specification&lt;/a&gt; that gives me hope for the future:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It is expected that a future extension to container queries will allow querying an element based on the position fallback it’s
using, enabling the sort of conditional styling not allowed by this restricted list.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In the meantime, we must resort to good old JavaScript. When the menu panel is opened, we call the following method of
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;MenuNavigationHandler&lt;/code&gt;  class to set the appropriate &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;transform-origin&lt;/code&gt; :&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;setTransformOriginOnMenuPanel&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; menuPanelPos&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;menuEl&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;getBoundingClientRect&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; menuTriggerBtnPos&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;menuBtn&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;getBoundingClientRect&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; originY&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; menuTriggerBtnPos&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;y&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; menuPanelPos&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;y&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; ?&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;quot;bottom&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;quot;top&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; originX&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; menuTriggerBtnPos&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; menuPanelPos&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; ?&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;quot;right&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;quot;left&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;    this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;menuEl&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;setAttribute&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;style&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;`transform-origin: &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;originY&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; ${&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;originX&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;;`&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I know it’s a bit dirty. But it works! At least in Chrome and Edge. I’ll have to thoroughly test the whole custom menu in
Firefox and Safari when they finally support CSS anchor positioning.&lt;/p&gt;
&lt;h2 id=&quot;bonus-custom-menu-in-angular&quot;&gt;Bonus: Custom Menu in Angular&lt;/h2&gt;
&lt;p&gt;If you don’t know or care about the JavaScript framework &lt;a href=&quot;https://angular.dev/&quot;&gt;Angular&lt;/a&gt;, please skip this section.&lt;/p&gt;
&lt;p&gt;You’re still here? Alright, then check out my &lt;a href=&quot;https://github.com/alexlehner86/accessible-popover-menu/&quot;&gt;Accessible Popover Menu project&lt;/a&gt;.
It includes the custom directives &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;CustomMenuTrigger&lt;/code&gt; , &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;CustomMenu&lt;/code&gt; 
and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;CustomMenuItem&lt;/code&gt; . These directives encapsulate all the functionality I’ve described in this article
so far. You can use them to efficiently create accessible menu components in your Angular project.&lt;/p&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;Using Popover API and CSS Anchor Positioning is a blast! They make it so much easier to create complex widgets like a
custom menu, as I’ve shown you. I’ll do a thorough test run of the functionality in Firefox and Safari as soon as they also
support anchor positioning. But I’m very optimistic! 🤩&lt;/p&gt;
&lt;p&gt;I hope this article inspires you to experiment with these new web features yourself. I’m curious to see what kind of widgets
and components you build with them!&lt;/p&gt;
&lt;h2 class=&quot;post-update-title&quot;&gt; &lt;span aria-hidden=&quot;true&quot;&gt;&amp;raquo;&amp;nbsp;&lt;/span&gt;Update on 11/23/2025 &lt;/h2&gt; 
&lt;p&gt;Anchored container queries are supported in Chrome 143 now. So forget the use of JavaScript for animations in this article.
Go read my new article
&lt;a href=&quot;/blog/anchored-container-queries/&quot;&gt;“Flexible Menu Animation with Anchored Container Queries”&lt;/a&gt; instead.&lt;/p&gt;</content:encoded><category>accessibility</category><category>css</category><category>html</category><category>menu</category><category>popover</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_skateboarder_jump.jpg" length="0" type="image/jpeg"/></item><item><title>Make Screen Readers talk with the ARIA Notify API</title><link>https://www.oidaisdes.org/blog/aria-notify-first-look</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/aria-notify-first-look</guid><description>A first look at the new API that represents an alternative to ARIA live regions.</description><pubDate>Thu, 22 May 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A user presses the search button and the page content is updated to include the results of the search.
Or you click the &lt;span class=&quot;c-italic&quot;&gt;“Add to Shopping Cart”&lt;/span&gt;  button and the shopping cart icon in
the header receives a visual badge to indicate the added item. Typical workflows in modern websites.&lt;/p&gt;
&lt;p&gt;A sighted person can simply perceive the visual change of the page content. But what about blind and
visually impaired users? How can they perceive important changes that are not given focus? At the moment,
web developers have to use &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Guides/Live_regions&quot;&gt;ARIA live regions&lt;/a&gt;
to create status messages that are announced by screen readers.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-edmond-dantes-megaphone.DFdg2kJG_1wVGnY.webp&quot; srcset=&quot;/_astro/pexels-edmond-dantes-megaphone.DFdg2kJG_Z2p6vgj.webp 640w, /_astro/pexels-edmond-dantes-megaphone.DFdg2kJG_Z5JGJK.webp 750w, /_astro/pexels-edmond-dantes-megaphone.DFdg2kJG_Z5mTMC.webp 828w, /_astro/pexels-edmond-dantes-megaphone.DFdg2kJG_Z1jTfWC.webp 1080w, /_astro/pexels-edmond-dantes-megaphone.DFdg2kJG_ZgEpoJ.webp 1280w, /_astro/pexels-edmond-dantes-megaphone.DFdg2kJG_1wVGnY.webp 1600w&quot; alt=&quot;Woman speaking into a megaphone.&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1067&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Edmond Dantès / pexels.com&lt;/p&gt;
&lt;p&gt;Unfortunately, ARIA live regions are tightly coupled with DOM elements that need to be updated. But
in some cases it would be more straightforward to simply let the screen reader announce a specific text.
This is the idea behind the new &lt;a href=&quot;https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/Accessibility/AriaNotify/explainer.md&quot;&gt;ARIA Notify API&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Microsoft Edge has recently implemented the new API as a
&lt;a href=&quot;https://blogs.windows.com/msedgedev/2025/05/05/creating-a-more-accessible-web-with-aria-notify/&quot;&gt;developer and origin trial&lt;/a&gt;.
So, I went ahead and created a demo project to test the new functionality. Here’s what I think.&lt;/p&gt;
&lt;h2 id=&quot;how-does-aria-notify-work&quot;&gt;How does ARIA Notify work?&lt;/h2&gt;
&lt;p&gt;ARIA Notify is an imperative notification API designed to replace the usage of ARIA live regions in
situations where a visual live region isn’t necessary. The API provides an ergonomic way to tell
assistive technologies, such as screen readers, exactly what to announce to users and when.&lt;/p&gt;
&lt;p&gt;Developers can call the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;ariaNotify()&lt;/code&gt;  method with the text to be announced to
the user. Here’s an example:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;document&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;ariaNotify&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;This is an audible notification&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Optionally, you can set the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;priority&lt;/code&gt;  option to indicate how the screen reader
should rank the notification with respect to other, pending, notifications:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;document&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;ariaNotify&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;Critical error&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, { &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;priority:&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;quot;high&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; });&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Want to give it a try?&lt;/p&gt;
&lt;h2 id=&quot;demo-online-shop-with-shopping-cart&quot;&gt;Demo: Online Shop with Shopping Cart&lt;/h2&gt;
&lt;p&gt;I’ve created a CodePen demo of an online shop named &lt;span class=&quot;c-italic&quot;&gt;“The Shop”&lt;/span&gt; . You can add products
to the shopping cart like &lt;span class=&quot;c-italic&quot;&gt;“Fancy Stuff”&lt;/span&gt;  or &lt;span class=&quot;c-italic&quot;&gt;“Useless Junk”&lt;/span&gt; .
The shopping cart will visually indicate that products were added. Screen reader users will hear a message
like, e.g., &lt;span class=&quot;c-italic&quot;&gt;“Item Fancy Stuff was added to shopping cart.”&lt;/span&gt; &lt;/p&gt;
&lt;iframe title=&quot;Shop Demo with ARIA Notify API&quot; src=&quot;https://codepen.io/alexlehner86/embed/VYYNQyr?default-tab=result&quot; loading=&quot;lazy&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/alexlehner86/pen/VYYNQyr&quot;&gt;
Shop Demo with ARIA Notify API&lt;/a&gt; by Alexander Lehner (&lt;a href=&quot;https://codepen.io/alexlehner86&quot;&gt;@alexlehner86&lt;/a&gt;)
on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;&lt;/iframe&gt;
&lt;p&gt;At the moment of writing this blog post, the ARIA Notify API is only supported as an origin trial in Microsoft
Edge. You need to install &lt;a href=&quot;https://www.microsoft.com/en-us/edge/download/insider&quot;&gt;Edge Canary&lt;/a&gt; and start the
browser with the following command:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;&amp;quot;C:\Users\[username]\AppData\Local\Microsoft\Edge SxS\Application\msedge.exe&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; --enable-blink-features=AriaNotify&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt; -enable-blink-features=AriaNotify&lt;/code&gt;  flag enables the ARIA Notify API. Now you should
hear your screen reader announce a message when you add a product to the shopping cart. I successfully tested
this with current versions of &lt;a href=&quot;https://www.nvaccess.org/download/&quot;&gt;NVDA&lt;/a&gt; and &lt;a href=&quot;https://www.freedomscientific.com/products/software/jaws/&quot;&gt;JAWS&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;first-impressions&quot;&gt;First Impressions&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;I like how straightforward and easy to use the new API is. You simply call &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;ariaNotify()&lt;/code&gt; 
and the screen reader announces the message. Awesome! 🤩&lt;/li&gt;
&lt;li&gt;The W3C will have to update their list of sufficient techniques in
&lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/status-messages.html&quot;&gt;WCAG 4.1.3 Status Messages&lt;/a&gt;. 😅&lt;/li&gt;
&lt;li&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;priority&lt;/code&gt;  option didn’t really make a difference in my test cases. I’ve
&lt;a href=&quot;https://codepen.io/alexlehner86/pen/KwwYGwJ&quot;&gt;created another demo&lt;/a&gt; with a toggle for using high or normal
priority. But the screen reader announcements came at the same time. Maybe I misunderstood something. 😩&lt;/li&gt;
&lt;li&gt;Web developers will have to be very careful with the new API. When it’s that easy to make a screen reader
announce text, then there’s a danger of flooding users with too many messages. I’m thinking about autoplay
carousels that constantly announce status messages! 😨&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Anyway. We’re still in a very early, experimental phase. I’ll wait for other browsers to also implement the
new API and let it mature a bit. Then I’ll test it on more devices, especially on mobile.&lt;/p&gt;
&lt;p&gt;In general, I’m excited and optimistic about the ARIA Notify API.&lt;/p&gt;</content:encoded><category>accessibility</category><category>aria</category><category>javascript</category><category>screenreader</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_megaphone.jpg" length="0" type="image/jpeg"/></item><item><title>Date and Time Management with the Temporal API</title><link>https://www.oidaisdes.org/blog/temporal-api-first-look</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/temporal-api-first-look</guid><description>It&apos;s more reliable than Date and offers formatting options and time zone support.</description><pubDate>Thu, 17 Apr 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Are you fed up with the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Date&lt;/code&gt;  object in JavaScript? Me too! Lucky for us,
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Temporal&lt;/code&gt;  API is just around the corner. This new namespace comprises several
classes for date and time management, including built-in time zone and calendar representation.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-koolshooters-alarm-clock.DNReWSNw_Z1VcMh4.webp&quot; srcset=&quot;/_astro/pexels-koolshooters-alarm-clock.DNReWSNw_1NJApl.webp 640w, /_astro/pexels-koolshooters-alarm-clock.DNReWSNw_qeDqE.webp 750w, /_astro/pexels-koolshooters-alarm-clock.DNReWSNw_2o83eT.webp 828w, /_astro/pexels-koolshooters-alarm-clock.DNReWSNw_Z1jCX1k.webp 1080w, /_astro/pexels-koolshooters-alarm-clock.DNReWSNw_Z1cP0pB.webp 1280w, /_astro/pexels-koolshooters-alarm-clock.DNReWSNw_Z1VcMh4.webp 1600w&quot; alt=&quot;A woman rests her arms on a table, looking at the big alarm clock next to her.&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1067&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © KoolShooters / pexels.com&lt;/p&gt;
&lt;p&gt;The new API is already available in &lt;a href=&quot;https://blog.nightly.mozilla.org/&quot;&gt;Firefox Nightly&lt;/a&gt;. We’ll quickly
cover the main features of &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Temporal&lt;/code&gt;  and then look at some code snippets I’ve
compiled.&lt;/p&gt;
&lt;h2 id=&quot;high-level-overview&quot;&gt;High-Level Overview&lt;/h2&gt;
&lt;p&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Temporal&lt;/code&gt;  API exposes over 200 utility methods via several classes. That’s a
lot! So I won’t cover all of them but just name the most important features.&lt;/p&gt;
&lt;p&gt;There are several objects for working with plain dates and times, without a time zone:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Temporal.PlainDate&lt;/code&gt;  represents a calendar date without a time or time zone.
Example: 2025-04-14&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Temporal.PlainTime&lt;/code&gt;  represents a time without a date or time zone. Example:
21:10:30.025&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Temporal.PlainDateTime&lt;/code&gt;  represents a date and time without a time zone.
Example: 2025-04-14T21:10:30.025&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To represent a unique point in time we use the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Temporal.Instant&lt;/code&gt;  object. It is
semantically the same as &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Date&lt;/code&gt; , but more precise (nanosecond precision).&lt;/p&gt;
&lt;p&gt;At last we arrive at the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Temporal.ZonedDateTime&lt;/code&gt;  object, which combines an instant,
a time zone, and a calendar system. Example: &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;2025-04-16T21:22:26.384+02:00[Europe/Vienna]&lt;/code&gt; .&lt;/p&gt;
&lt;p&gt;Furthermore, we can get the current time in various formats using the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Temporal.Now&lt;/code&gt; 
object. And the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Temporal.Duration&lt;/code&gt;  represents a difference between two time points,
which can also be used in date/time calculations.&lt;/p&gt;
&lt;h2 id=&quot;code-snippets&quot;&gt;Code Snippets&lt;/h2&gt;
&lt;p&gt;I’ve compiled a &lt;a href=&quot;https://github.com/alexlehner86/temporal-api-code-snippets/&quot;&gt;list of code snippets&lt;/a&gt;
for working with the new
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal&quot;&gt;Temporal API&lt;/a&gt;
in JavaScript. Here’s a few examples:&lt;/p&gt;
&lt;h3 id=&quot;create-a-new-plain-date-object-and-access-parts-of-it&quot;&gt;Create a new plain date object and access parts of it&lt;/h3&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; calendarDate&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; Temporal&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;PlainDate&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;2025-04-09&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;calendarDate&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;day&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;// 9&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;calendarDate&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;dayOfWeek&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;// 3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;calendarDate&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;month&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;// 4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;calendarDate&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;year&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;// 2025&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;add-a-duration-to-an-immutable-plain-time-object&quot;&gt;Add a duration to an immutable plain time object&lt;/h3&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; t1&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; Temporal&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;PlainTime&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;14&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;55&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;250&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;// &amp;quot;14:55:10.25&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; t2&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; t1&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;seconds:&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 5000&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;t2&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;toString&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(); &lt;/span&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;// &amp;quot;16:18:30.25&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;language-sensitive-formatting-of-a-zoned-datetime&quot;&gt;Language-sensitive formatting of a zoned datetime&lt;/h3&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; datetime&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; Temporal&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;ZonedDateTime&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;2020-10-15T08:30Z[America/New_York]&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;datetime&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;toLocaleString&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;en-US&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;// &amp;quot;10/15/2020, 4:30:00 AM EDT&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;compare-two-instants&quot;&gt;Compare two instants&lt;/h3&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; inst1&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; Temporal&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;Instant&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;2022-07-10T12:00Z&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; inst2&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; Temporal&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;Instant&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;2023-01-01T15+01:00&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;inst1&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;equals&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;inst2&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);  &lt;/span&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;// false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;Temporal&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;Instant&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;compare&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;inst1&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;inst2&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;// -1 (is before)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;round-a-duration-to-a-specified-unit&quot;&gt;Round a duration to a specified unit&lt;/h3&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; duration&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; Temporal&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;PlainTime&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;12:30&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;until&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;17:45&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;// &amp;quot;PT5H15M&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;duration&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; duration&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;round&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;hours&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;// &amp;quot;PT5H&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;browser-support&quot;&gt;Browser Support&lt;/h2&gt;
&lt;p&gt;Are you hyped already? I sure am! And it gets even better: Firefox will soon be the first browser to
&lt;a href=&quot;https://groups.google.com/a/mozilla.org/g/dev-platform/c/RtsRo93ygO4/m/2YzM42GUBwAJ&quot;&gt;ship Temporal in stable release&lt;/a&gt;.
Firefox 139 is due on May 27.&lt;/p&gt;
&lt;p&gt;The implementation in other browsers is still a work in progress
(&lt;a href=&quot;https://issues.chromium.org/issues/42201538&quot;&gt;Chromium&lt;/a&gt;, &lt;a href=&quot;https://bugs.webkit.org/show_bug.cgi?id=223166&quot;&gt;WebKit/Safari&lt;/a&gt;).
But I’m sure they’ll get there soon. In the meantime: Get familiar
with &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Temporal&lt;/code&gt;  in Firefox Nightly. 😉&lt;/p&gt;</content:encoded><category>calendar</category><category>date</category><category>javascript</category><category>temporal</category><category>time</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_alarm_clock.jpg" length="0" type="image/jpeg"/></item><item><title>My Favorite Tools for Web Accessibility Testing</title><link>https://www.oidaisdes.org/blog/accessibility-testing-tools</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/accessibility-testing-tools</guid><description>A selection of bookmarklets, browser extensions and other accessibility testing tools.</description><pubDate>Sun, 30 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Web accessibility has many facets: Operation with the keyboard and other input devices, alternative
texts for images, descriptive headings and error texts, etc. The range of tools for testing the
accessibility of websites is just as diverse.&lt;/p&gt;
&lt;p&gt;First things first: there is no &lt;span class=&quot;c-italic&quot;&gt;single power tool&lt;/span&gt;  that automatically detects
all barriers and ideally also removes them straight away. This also applies to AI-based accessibility
tools. Yes, artificial intelligence has great potential, but
&lt;a href=&quot;https://adrianroselli.com/2023/06/no-ai-will-not-fix-accessibility.html&quot;&gt;current tools cannot replace a comprehensive accessibility test&lt;/a&gt;.
Even if certain people claim otherwise in the frenzy of &lt;a href=&quot;https://www.forbes.com/sites/christianstadler/2024/09/06/the-generative-ai-hype-is-almost-over-whats-next/&quot;&gt;AI hype&lt;/a&gt;.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-thirdman-garden-tools.BBhn-nqG_1mivqq.webp&quot; srcset=&quot;/_astro/pexels-thirdman-garden-tools.BBhn-nqG_ZL8ANE.webp 640w, /_astro/pexels-thirdman-garden-tools.BBhn-nqG_Z2wRAX6.webp 750w, /_astro/pexels-thirdman-garden-tools.BBhn-nqG_1h7dE5.webp 828w, /_astro/pexels-thirdman-garden-tools.BBhn-nqG_Z2e3WOO.webp 1080w, /_astro/pexels-thirdman-garden-tools.BBhn-nqG_25jaXM.webp 1280w, /_astro/pexels-thirdman-garden-tools.BBhn-nqG_1mivqq.webp 1600w&quot; alt=&quot;Various garden tools and plants on a table.&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1067&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Thirdman / pexels.com&lt;/p&gt;
&lt;p&gt;We need the right tools for the delicate little plant of accessibility to flourish. Here is my personal
selection of free bookmarklets, browser extensions and accessibility testing tools.&lt;/p&gt;
&lt;h2 id=&quot;structure-and-semantics&quot;&gt;Structure and Semantics&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://wave.webaim.org/&quot;&gt;WAVE (Web Accessibility Evaluation Tools)&lt;/a&gt;: An accessibility analysis tool
from WebAIM. Available as a browser extension for Firefox, Chrome and Edge. I find the structure view
particularly useful, where you can see at a glance whether meaningful landmarks
(&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;header&lt;/code&gt; , &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;main&lt;/code&gt; , etc.) and heading levels have been defined.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://firefox-source-docs.mozilla.org/devtools-user/accessibility_inspector/&quot;&gt;Firefox Accessibility Inspector&lt;/a&gt;
is a built-in component of the Firefox developer tools. Do you want to know what information an interactive
element communicates to assistive technologies? Simply right-click on it and
select &lt;span class=&quot;c-italic&quot;&gt;“Inspect Accessibility Properties”&lt;/span&gt; . Firefox opens the “Accessibility” tab
in the developer tools and jumps to the corresponding node in the
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/Accessibility_tree&quot;&gt;accessibility tree&lt;/a&gt;.
Debugging has never been so easy! 😍&lt;/li&gt;
&lt;li&gt;Test with &lt;strong&gt;screen readers&lt;/strong&gt;: No accessibility audit is complete without screen
reader testing. In view of limited budgets in projects, it is not possible to test with
&lt;a href=&quot;https://en.wikipedia.org/wiki/List_of_screen_readers&quot;&gt;all screen readers on all platforms&lt;/a&gt;. Based on
&lt;a href=&quot;https://webaim.org/projects/screenreadersurvey10/&quot;&gt;current statistics&lt;/a&gt;, I have therefore defined the
following test scenarios:
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nvaccess.org/&quot;&gt;NVDA&lt;/a&gt; in Windows&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.apple.com/accessibility/vision/&quot;&gt;VoiceOver&lt;/a&gt; in iOS&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://support.google.com/accessibility/android/answer/6283677?hl=en&quot;&gt;TalkBack&lt;/a&gt; in Android&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If you have never tested with the screen reader, then read my article
&lt;a href=&quot;/blog/a11y-audits-screenreader/&quot;&gt;“5 Tips for getting started with Accessibility Audits using a screen reader”&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ideal for testing the WCAG criteria &lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/info-and-relationships.html&quot;&gt;1.3.1 Info and Relationships&lt;/a&gt;
and &lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/name-role-value.html&quot;&gt;4.1.2 Name, Role, Value&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;keyboard-operability&quot;&gt;Keyboard Operability&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Test with &lt;strong&gt;keyboard&lt;/strong&gt;: Use the tab key to access the interactive elements on the page
(buttons, links, etc.). Does the focus order make sense? Can keyboard users reach and activate all
interactive elements? Is the focused element visibly highlighted? On a smartphone or tablet, you can simply
connect a Bluetooth keyboard for testing.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://chromewebstore.google.com/detail/taba11y-tab-order-accessi/aocppmckdocdjkphmofnklcjhdidgmga&quot;&gt;taba11y&lt;/a&gt;:
This useful browser extension calculates the tab order of all elements and displays it visually, either
by drawing a path or by highlighting the elements.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ideal for testing the WCAG criteria &lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/keyboard.html&quot;&gt;2.1.1 Keyboard&lt;/a&gt;,
&lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/no-keyboard-trap&quot;&gt;2.1.2 No Keyboard Trap&lt;/a&gt;,
&lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/focus-order&quot;&gt;2.4.3 Focus Order&lt;/a&gt;, and
&lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/focus-visible&quot;&gt;2.4.7 Focus Visible&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;responsive-content&quot;&gt;Responsive Content&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.microsoft.com/en-us/edge/learning-center/how-to-change-font-size?form=MA13I2&quot;&gt;Browser settings&lt;/a&gt;:
Change the default font size of your browser to check whether the website automatically adjusts the text
size. Most browsers, such as Edge, only allow you to choose from predefined options such as “Small”,
“Medium” and “Large”. In &lt;a href=&quot;https://support.mozilla.org/en-US/kb/change-fonts-and-colors-websites-use&quot;&gt;Firefox&lt;/a&gt;,
on the other hand, users can define a specific pixel value as the default font size.&lt;/li&gt;
&lt;li&gt;Alternatively, you can use the browser’s zoom function (&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;CTRL&lt;/code&gt; 
and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;+&lt;/code&gt;  key) to enlarge the entire page content in proportion to the font size.&lt;/li&gt;
&lt;li&gt;Use the &lt;a href=&quot;https://codepen.io/stevef/full/YLMqbo&quot;&gt;text spacing bookmarklet&lt;/a&gt; or a browser extension (e.g.
&lt;a href=&quot;https://chromewebstore.google.com/detail/editor-for-textlayout/amnelgbfbdlfjeaobejkfmjjnmeddaoj&quot;&gt;Editor for Textlayout&lt;/a&gt;)
to set the values for line height, spacing following paragraphs, letter spacing and word spacing to the
maximum required values. No content should be cut off or overlap.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ideal for testing the WCAG criteria &lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/resize-text.html&quot;&gt;1.4.4 Resize Text&lt;/a&gt;,
&lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/reflow&quot;&gt;1.4.10 Reflow&lt;/a&gt;,
and &lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/text-spacing&quot;&gt;1.4.12 Text Spacing&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;target-size-of-interactive-elements&quot;&gt;Target Size of Interactive Elements&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://html5accessibility.com/stuff/2023/08/28/quick-and-very-dirty-target-size-checker/&quot;&gt;Target Size Bookmarklet&lt;/a&gt;:
It identifies interactive elements, calculates their center and draws a semi-transparent circle of 24 by 24
pixels around the center of the element: A green circle with a thick border means that the target size is
sufficient. Elements with a blue circle should be examined manually.&lt;/li&gt;
&lt;li&gt;This way, you can find buttons and links much more quickly where users with motor impairments may have
problems clicking or tapping.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ideal for testing the WCAG criterion &lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/target-size-minimum&quot;&gt;2.5.8 Target Size (Minimum)&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;minimum-contrast&quot;&gt;Minimum Contrast&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/overview&quot;&gt;Chrome Lighthouse&lt;/a&gt; is part of the developer
tools in Chrome. The Lighthouse accessibility check reliably finds the majority of elements with too
low a contrast ratio.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/windows/powertoys/#color-picker&quot;&gt;PowerToys Color Picker&lt;/a&gt;:
The Microsoft PowerToys are a collection of utilities for power users. With the key
combination &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;WIN&lt;/code&gt; +&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Shift&lt;/code&gt; +&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;C&lt;/code&gt; 
you can activate the color picker at any time and extract the color value of a pixel on the screen.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webaim.org/resources/contrastchecker/&quot;&gt;WebAIM Contrast Checker&lt;/a&gt;: Simple tool to check the
contrast ratio of a font color to the background color. A particularly useful feature is that you can
share the selected color values and their evaluation as a permalink.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ideal for testing the WCAG criteria &lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html&quot;&gt;1.4.3 Contrast (Minimum)&lt;/a&gt;
und &lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/non-text-contrast&quot;&gt;1.4.11 Non-text Contrast&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;additional-links&quot;&gt;Additional Links&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/WAI/test-evaluate/tools/list/&quot;&gt;Web Accessibility Evaluation Tools List  (W3C)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://accessibility.huit.harvard.edu/testing&quot;&gt;Accessibility Testing Tools and Practices (Harvard University)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>accessibility</category><category>bookmarklet</category><category>browser</category><category>screenreader</category><category>testing</category><category>tools</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_garden_tools.jpg" length="0" type="image/jpeg"/></item><item><title>Accessibility Engineering — Let the Web Platform do the Work</title><link>https://www.oidaisdes.org/blog/accessibility-engineering-web-platform</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/accessibility-engineering-web-platform</guid><description>Harness the power of native buttons, dialogs, form controls, and disclosure widgets.</description><pubDate>Mon, 03 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Being a web developer is hard. You’re handed some written requirements and, if you’re lucky,
a visual design. You start work on the new feature: You add HTML elements, style them with CSS,
and implement business logic with JavaScript. You need to think about usability, web security,
page speed, data management, and so on.&lt;/p&gt;
&lt;p&gt;You take a deep breath and tell yourself: &lt;span class=&quot;c-italic&quot;&gt;“I can do this!”&lt;/span&gt; &lt;/p&gt;
&lt;p&gt;Your project manager comes in and asks: &lt;span class=&quot;c-italic&quot;&gt;“The website will also be accessible, right?”&lt;/span&gt; 
You panic and start to research web accessibility. You’re flooded with information. Some of it
contradicting. You ask ChatGPT for help. It shows you overcomplex code ridden with
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA&quot;&gt;ARIA&lt;/a&gt; attributes. You sigh,
thinking: &lt;span class=&quot;c-italic&quot;&gt;“That’s a lot of work!”&lt;/span&gt; &lt;/p&gt;
&lt;p&gt;I have good news for you: Accessibility doesn’t have to be this exhausting. It can actually be
quite simple and, I dare say, beautiful. All you need to do is embrace the
&lt;a href=&quot;https://en.wikipedia.org/wiki/Web_platform&quot;&gt;web platform&lt;/a&gt; and let it do the work!&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-thisisengineering-code-woman.CY19Z2LT_Z1212uI.webp&quot; srcset=&quot;/_astro/pexels-thisisengineering-code-woman.CY19Z2LT_1Xeumo.webp 640w, /_astro/pexels-thisisengineering-code-woman.CY19Z2LT_Z1x5agx.webp 750w, /_astro/pexels-thisisengineering-code-woman.CY19Z2LT_1tAbEK.webp 828w, /_astro/pexels-thisisengineering-code-woman.CY19Z2LT_f2IKu.webp 1080w, /_astro/pexels-thisisengineering-code-woman.CY19Z2LT_5Y5Dg.webp 1280w, /_astro/pexels-thisisengineering-code-woman.CY19Z2LT_Z1212uI.webp 1600w&quot; alt=&quot;Lines of code are projected onto a woman who&apos;s looking at the camera.&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1067&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © ThisIsEngineering / pexels.com&lt;/p&gt;
&lt;p&gt;We’ll take a quick look at the basic tools of the web and how to use them efficiently. Then I’ll
give you several specific examples of web features with accessibility baked in.&lt;/p&gt;
&lt;h2 id=&quot;the-basic-tools-of-accessibility-engineering&quot;&gt;The Basic Tools of Accessibility Engineering&lt;/h2&gt;
&lt;p&gt;The web platform is a collection of technologies developed as open standards by the
&lt;a href=&quot;https://www.w3.org/&quot;&gt;World Wide Web Consortium&lt;/a&gt; and other standardization bodies. These technologies
include HTML, CSS, JavaScript and WAI-ARIA. These building blocks of the web enable us to design websites
that are accessible to all people.&lt;/p&gt;
&lt;p&gt;Then why are so many web developers struggling with accessibility? I think there are two main reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Over-reliance on external libraries.&lt;/li&gt;
&lt;li&gt;Insufficient experience with native web features.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Most junior developers nowadays learn web development based on frameworks like &lt;a href=&quot;https://angular.dev/&quot;&gt;Angular&lt;/a&gt;,
&lt;a href=&quot;https://react.dev/&quot;&gt;React&lt;/a&gt; or &lt;a href=&quot;https://vuejs.org/&quot;&gt;Vue.js&lt;/a&gt;. They learn everything about components and
data management, but hardly familiarize themselves with native HTML elements and advanced CSS features.&lt;/p&gt;
&lt;p&gt;I don’t blame any of them! Modern JavaScript frameworks and UI libraries offer powerful features that help
us implement complex web applications. But they are another level of abstraction. They take us away from
the essential building blocks of the web. So what should you do?&lt;/p&gt;
&lt;h3 id=&quot;html-first-and-the-rule-of-least-power&quot;&gt;HTML First and The Rule of Least Power&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://en.wikipedia.org/wiki/Rule_of_least_power&quot;&gt;rule of least power&lt;/a&gt; is a design principle that
suggests choosing the least powerful language suitable for a given purpose. What does this mean for web
developers? If you can do something with HTML, use HTML. Need to adapt the styling? Use CSS. If you can’t
do it with HTML and CSS alone, use JavaScript and &lt;a href=&quot;https://www.w3.org/WAI/standards-guidelines/aria/&quot;&gt;WAI-ARIA&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Native HTML elements are built to work on multiple browsers and with different types of assistive technology,
like screen readers. They’re usually more robust and reliable than custom solutions. Next time you start to
implement a new feature, look for a solution in the following order:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;HTML&lt;/li&gt;
&lt;li&gt;CSS&lt;/li&gt;
&lt;li&gt;JavaScript&lt;/li&gt;
&lt;li&gt;WAI-ARIA&lt;/li&gt;
&lt;li&gt;External Libraries&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As a first step, I always
search for a native solution on &lt;a href=&quot;https://developer.mozilla.org/&quot;&gt;MDN Web Docs&lt;/a&gt;. If I can’t do something with
HTML and CSS alone, I start to research the proper use of ARIA attributes and JavaScript to create an accessible
solution. The &lt;a href=&quot;https://www.w3.org/WAI/ARIA/apg/&quot;&gt;ARIA Authoring Practices Guide (APG)&lt;/a&gt; provides all the
information you need.&lt;/p&gt;
&lt;p&gt;Why are external libraries last on the list? Because they create an additional dependency for your project.
Once you’ve commited to using a UI component library, you’re usually stuck with it. That’s why you should
make sure to pick an accessible UI library. Go read my
&lt;a href=&quot;/blog/accessible-ui-component-libraries/&quot;&gt;“Checklist for Accessible UI Component Libraries”&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;the-current-state-of-the-web&quot;&gt;The Current State of the Web&lt;/h3&gt;
&lt;p&gt;The web platform is constantly evolving. New HTML elements, CSS properties and Web APIs are specified and
implemented by browsers every day. Initiatives like &lt;a href=&quot;https://wpt.fyi/interop-2024&quot;&gt;Interop 2024&lt;/a&gt; help to
improve the interoperability of the web.&lt;/p&gt;
&lt;p&gt;For web developers, it’s way easier and straightforward to create accessible websites today than it was
10 years ago. I admit, not everything can be done with HTML and CSS alone. Right now, you still need ARIA
and JavaScript to implement a &lt;a href=&quot;https://www.w3.org/WAI/ARIA/apg/patterns/tabs/&quot;&gt;tab list&lt;/a&gt; or
&lt;a href=&quot;https://www.w3.org/WAI/ARIA/apg/patterns/tooltip/&quot;&gt;custom tooltips&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But I want to focus on the bright side! Let’s take a look at some native HTML features that make it very
easy and convenient to create robust, accessible websites.&lt;/p&gt;
&lt;h2 id=&quot;examples-of-native-html-features&quot;&gt;Examples of Native HTML Features&lt;/h2&gt;
&lt;h3 id=&quot;the-button-element-a-powerful-allrounder&quot;&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;button&lt;/code&gt;  element: A Powerful Allrounder&lt;/h3&gt;
&lt;p&gt;Chances are, the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;button&lt;/code&gt;  element is older than you! It was first introduced
in the &lt;a href=&quot;https://www.w3.org/TR/REC-html40-971218/&quot;&gt;HTML 4.0 specification&lt;/a&gt; in December 1997. This means,
buttons have been around for quite a while. But still, many web developers underestimate this powerful
and versatile HTML element. Some even think it’s a good idea to use a &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;div&lt;/code&gt;  element
instead. The horror! 😱&lt;/p&gt;
&lt;p&gt;Maybe you’re thinking: &lt;span class=&quot;c-italic&quot;&gt;“Alright, Romeo! Why are you so in love with the button element?”&lt;/span&gt; 
Let me answer with the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button&quot;&gt;short description by MDN&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &amp;lt;button&amp;gt; HTML element is an interactive element activated by a user with a mouse, keyboard, finger,
voice command, or other assistive technology. Once activated, it then performs an action, such as submitting
a form or opening a dialog.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;button&lt;/code&gt;  element was designed to work well for all users. You can click on it
with a mouse. You can focus a button with the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;TAB&lt;/code&gt;  key and activate it with
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Enter&lt;/code&gt;  or &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Space&lt;/code&gt;  key. When you navigate to the button
using a screen reader, it will be able to tell you that this is a button that can be activated.&lt;/p&gt;
&lt;p&gt;Browsers also apply a default styling to HTML buttons. Some web developers might find this annoying,
because they have to override these styles with CSS. They might pick the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;div&lt;/code&gt;  element
instead and slap a &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;click&lt;/code&gt;  event handler on it, thinking that’s enough. Well, it’s
not!&lt;/p&gt;
&lt;p&gt;There’s a big difference between &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;button&lt;/code&gt;  and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;div&lt;/code&gt;  elements!
A button will trigger the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;click&lt;/code&gt;  event handler for all types of user interaction:
mouse, keyboard, screen reader, and so on. The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;div&lt;/code&gt;  element, on the other hand, will
only trigger on mouse or touch interaction.
To &lt;a href=&quot;https://theadminbar.com/accessibility-weekly/divs-are-not-buttons/&quot;&gt;turn a div into an accessible button&lt;/a&gt;,
you need to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add a &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;tabindex&lt;/code&gt;  to make it keyboard focusable.&lt;/li&gt;
&lt;li&gt;Show a visible focus indicator when the button receives focus.&lt;/li&gt;
&lt;li&gt;Add key event handlers for the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Enter&lt;/code&gt;  and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Space&lt;/code&gt;  key.&lt;/li&gt;
&lt;li&gt;Add a &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;role&lt;/code&gt;  attribute to tell screen reader users it’s a button.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Wow, that’s a lot of work and code bloat! An implementation using a native button instead will always be
easier to read and maintain. If you’re still not convinced, go read my article
&lt;a href=&quot;/blog/3-ways-web-devs-benefit-accessibility/&quot;&gt;“3 Ways how Web Developers also benefit from Accessibility”&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That’s already a lot of text about buttons. But there’s one more argument I’d like to make: Native buttons
are still gaining more superpowers!&lt;/p&gt;
&lt;p&gt;The latest upgrade is thanks to
the new &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Popover_API&quot;&gt;Popover API&lt;/a&gt;. You can use
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;popovertarget&lt;/code&gt;  attribute to turn the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;button&lt;/code&gt;  element
into a popover control button. Check out this menu button demo (currently only works in Chromium browsers):&lt;/p&gt;
&lt;iframe title=&quot;Accessible Menu with Popover API&quot; src=&quot;https://codepen.io/alexlehner86/embed/rNQmERq?default-tab=result&quot; loading=&quot;lazy&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/alexlehner86/pen/rNQmERq&quot;&gt;
Accessible Menu with Popover API&lt;/a&gt; by Alexander Lehner (&lt;a href=&quot;https://codepen.io/alexlehner86&quot;&gt;@alexlehner86&lt;/a&gt;)
on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;&lt;/iframe&gt;
&lt;p&gt;There are so many use cases for buttons with attached popovers: Menus, tooltips, date pickers, etc.
If you’re new to the topic, you can take a look at the following articles I’ve written:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/popover-api-accessibility/&quot;&gt;“Make your content pop with the Popover API and CSS Anchor Positioning”&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/accessible-navigation-menu/&quot;&gt;“How to build Accessible Navigation Menus with the Popover API”&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/native-dialog-and-popover/&quot;&gt;“Native Dialogs and the Popover API — What you need to know”&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But we’re not done yet! The next button upgrade will arrive with the (currently experimental)
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Invoker_Commands_API&quot;&gt;Invoker Commands API&lt;/a&gt;.
This API provides a way to declaratively assign behaviors to buttons, like opening or closing a modal
dialog. Awesome! 🥰&lt;/p&gt;
&lt;p&gt;Oh, what a coincidence! Dialogs are the next native HTML feature I want to talk about.&lt;/p&gt;
&lt;h3 id=&quot;the-dialog-element-always-on-top&quot;&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;dialog&lt;/code&gt;  element: Always on top&lt;/h3&gt;
&lt;p&gt;Dialogs are an integral part of modern web user interfaces: From simple prompts for confirming an action
to content-heavy windows. The native &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;dialog&lt;/code&gt;  element makes it super easy to
open an accessible modal dialog on top of the other page content.&lt;/p&gt;
&lt;iframe src=&quot;https://alexlehner86.github.io/fancy-css-playground/#/dialog&quot; title=&quot;Demo Native Dialog Element&quot; loading=&quot;lazy&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;dialog&lt;/code&gt;  element is accessible by default. When you use
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;showModal()&lt;/code&gt;  method to open a modal dialog, the following happens:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The browser automatically moves focus to the first interactive element inside of the dialog.&lt;/li&gt;
&lt;li&gt;A screen reader will announce that the new content is part of a dialog.&lt;/li&gt;
&lt;li&gt;While the modal dialog is active, the content obscured by the dialog is inaccessible to all users. This
means that keyboard users can’t leave the dialog with the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;TAB&lt;/code&gt;  key, and a screen
reader’s virtual cursor is not allowed to leave the modal dialog as long as it remains open.&lt;/li&gt;
&lt;li&gt;Users can close the modal dialog with the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;ESC&lt;/code&gt;  key.&lt;/li&gt;
&lt;li&gt;On close, keyboard focus returns to the control that initially activated the dialog. This allows
keyboard and screen reader users to continue browsing from where they left off.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Of course, you don’t have to use the native &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;dialog&lt;/code&gt;  element. You could also
implement a custom, accessible dialog using ARIA and JavaScript. But why would you? Come on! Be a smart
web developer and let the web platform do the work. 😉&lt;/p&gt;
&lt;p&gt;If you’re unfamiliar with the native &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;dialog&lt;/code&gt;  element and want to know more, go
read my article &lt;a href=&quot;/blog/native-dialog-element/&quot;&gt;“Why you should use the Native Dialog Element”&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;form-controls-the-good-and-the-bad&quot;&gt;Form Controls: The Good and the Bad&lt;/h3&gt;
&lt;p&gt;Far too often, web developers use custom form controls to meet design needs – neglecting accessibility
in the process. You can do better! Modern browsers enable us to apply custom styling to most
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Forms/Basic_native_form_controls&quot;&gt;native form controls&lt;/a&gt;.
This way, we can create accessible web forms with a consistent look across all platforms.&lt;/p&gt;
&lt;p&gt;Native form controls like &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;input&lt;/code&gt;  or &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;select&lt;/code&gt;  are accessible
by default. They receive keyboard focus and can be activated with &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Enter&lt;/code&gt; 
or &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Space&lt;/code&gt; , e.g., to mark a checkbox as checked. They communicate their role and
current state to screen readers.&lt;/p&gt;
&lt;p&gt;The following demo shows an accessible web form with custom styles for the native select list and
radio buttons:&lt;/p&gt;
&lt;iframe title=&quot;Styling Native Form Controls&quot; src=&quot;https://codepen.io/alexlehner86/embed/mdqGLxZ?default-tab=result&quot; loading=&quot;lazy&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/alexlehner86/pen/mdqGLxZ&quot;&gt;
Styling Native Form Controls&lt;/a&gt; by Alexander Lehner (&lt;a href=&quot;https://codepen.io/alexlehner86&quot;&gt;@alexlehner86&lt;/a&gt;)
on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;&lt;/iframe&gt;
&lt;p&gt;Unfortunately, not all native form controls can be easily adapted with custom styles. Mozilla has a great
article on &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Forms/Styling_web_forms&quot;&gt;Styling web forms&lt;/a&gt;,
which I highly recommend. They categorize native form controls into three groups: “The good”, “The bad”,
and “The ugly”.&lt;/p&gt;
&lt;p&gt;In my opinion, the native elements for text inputs, radio buttons, checkboxes and simple select lists are
very easy to style. There is no reason to use custom elements instead. Unless you have a masochistic disposition.
Read my article &lt;a href=&quot;/blog/styling-accessible-web-forms/&quot;&gt;“Create Accessible Web Forms with Custom Styling”&lt;/a&gt; for
more information.&lt;/p&gt;
&lt;p&gt;Now, what about the rest? Several native form controls have internals that can’t be styled in CSS alone. These
include the color picker, date picker, file picker, and the drop-down list of the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;select&lt;/code&gt; 
element. In these cases, I understand the need for custom components. Just make sure they’re accessible.&lt;/p&gt;
&lt;p&gt;Lucky for us, the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;select&lt;/code&gt;  element will soon get an important upgrade. A customizable
version of the element is officially in &lt;a href=&quot;https://github.com/whatwg/html/issues/9799&quot;&gt;Stage 2 in the WHATWG&lt;/a&gt;,
with strong cross-browser interest and a prototype available in Chrome Canary. Read this
&lt;a href=&quot;https://developer.chrome.com/blog/rfc-customizable-select&quot;&gt;Chrome blog post&lt;/a&gt; for more information. 🤩&lt;/p&gt;
&lt;h3 id=&quot;disclosure-and-accordion-widgets-with-native-html&quot;&gt;Disclosure and accordion widgets with native HTML&lt;/h3&gt;
&lt;p&gt;The native &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;details&lt;/code&gt;  HTML element creates a disclosure widget in which information
is visible only when the widget is toggled open. The content of the nested &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;summary&lt;/code&gt; 
element provides the label for the disclosure widget. The perfect HTML elements for a FAQ page or an
expandable info section in an article.&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;details&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;What is HTML?&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    HTML is the standard markup language for web pages, defined by the W3C and WHATWG.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;details&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Historically it wasn’t possible to change the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;display&lt;/code&gt;  type of
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;details&lt;/code&gt;  element. This restriction has already been relaxed in Chromium browsers,
allowing you to use grid or flex layouts.
The article &lt;a href=&quot;https://developer.chrome.com/blog/styling-details&quot;&gt;“More options for styling &amp;lt;details&amp;gt;”&lt;/a&gt;
includes a really cool demo for an exclusive accordion.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Alright. This article turned out longer than I had intended. 😂&lt;/p&gt;
&lt;p&gt;I hope it helps you on your journey to becoming an accessibility engineer. Native HTML is powerful and
(mostly) accessible by default. If you keep this in mind, you’ll be alright.&lt;/p&gt;</content:encoded><category>accessibility</category><category>button</category><category>css</category><category>dialog</category><category>forms</category><category>html</category><category>popover</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_code_woman.jpg" length="0" type="image/jpeg"/></item><item><title>Placeholder Text needs Good Color Contrast</title><link>https://www.oidaisdes.org/blog/placeholder-text-color-contrast</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/placeholder-text-color-contrast</guid><description>Use the ::placeholder CSS pseudo-element to improve your website&apos;s accessibility.</description><pubDate>Fri, 20 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Does placeholder text in forms need to meet color contrast requirements? The short answer is: &lt;span class=&quot;c-italic&quot;&gt;“Yes, it does!”&lt;/span&gt; &lt;/p&gt;
&lt;p&gt;The long answer: Not all users have perfect vision with high contrast sensitivity. Especially when you get older,
it gets harder to recognize text as being separate from the background behind it when color contrast is low.
Therefore, you should always provide sufficient contrast between text and its background.&lt;/p&gt;
&lt;p&gt;This also applies to placeholder text in web forms or documents. The placeholder usually provides a useful hint
that describes the expected value of an input field. It isn’t purely decorative. So, all users should be able to
perceive the placeholder text.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-egor-komarov-book-rules.CdOie-0l_261M1S.webp&quot; srcset=&quot;/_astro/pexels-egor-komarov-book-rules.CdOie-0l_1R9Jb5.webp 640w, /_astro/pexels-egor-komarov-book-rules.CdOie-0l_ZSFA7i.webp 750w, /_astro/pexels-egor-komarov-book-rules.CdOie-0l_ZSiNaa.webp 828w, /_astro/pexels-egor-komarov-book-rules.CdOie-0l_ZKOajI.webp 1080w, /_astro/pexels-egor-komarov-book-rules.CdOie-0l_hpFea.webp 1280w, /_astro/pexels-egor-komarov-book-rules.CdOie-0l_261M1S.webp 1600w&quot; alt=&quot;An open book on a table with the word rules clearly visible.&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1067&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Egor Komarov / pexels.com&lt;/p&gt;
&lt;h2 id=&quot;requirements-for-minimum-color-contrast&quot;&gt;Requirements for minimum color contrast&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html&quot;&gt;Success Criterion 1.4.3 Contrast (Minimum)&lt;/a&gt; of WCAG 2.2
defines requirements for minimum color contrast. Text must have a minimum contrast ratio of 4.5 to 1 with the background, or 3 to 1
contrast ratio if its large text. The understanding document explicitly states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This Success Criterion applies to text in the page, &lt;strong&gt;including placeholder text&lt;/strong&gt; and text that is shown when
a pointer is hovering over an object or when an object has keyboard focus.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There’s lots of tools you can use to check the contrast ratio of two color values. I mostly use
the &lt;a href=&quot;https://webaim.org/resources/contrastchecker/&quot;&gt;WebAIM Contrast Checker&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;how-to-style-placeholder-text-in-web-forms&quot;&gt;How to style placeholder text in web forms&lt;/h2&gt;
&lt;p&gt;In most browsers, the default appearance of placeholder text is a light gray color by default. UI libraries also
sometimes use very light colors for placeholder text. This results in placeholder text with poor color contrast.&lt;/p&gt;
&lt;p&gt;Use the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;::placeholder&lt;/code&gt;  CSS pseudo-element to define a text color with sufficient color contrast:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;input::placeholder&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    color&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;#5b5b5b&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also change the font style and weight of your placeholder text. Take a look at my demo where you can compare your
browser’s default styling with the applied custom styles:&lt;/p&gt;
&lt;iframe title=&quot;Style placeholder text&quot; src=&quot;https://codepen.io/alexlehner86/embed/raBmOZq?default-tab=result&quot; loading=&quot;lazy&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/alexlehner86/pen/raBmOZq&quot;&gt;
Style placeholder text&lt;/a&gt; by Alexander Lehner (&lt;a href=&quot;https://codepen.io/alexlehner86&quot;&gt;@alexlehner86&lt;/a&gt;)
on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;&lt;/iframe&gt;
&lt;p&gt;A small change that highly improves the accessibility of your website. Sometimes it’s that easy! 😊&lt;/p&gt;
&lt;h2 id=&quot;useful-resources&quot;&gt;Useful Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html&quot;&gt;Understanding Success Criterion 1.4.3 Contrast (Minimum)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/::placeholder&quot;&gt;CSS pseudo-element ::placeholder (MDN)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>accessibility</category><category>css</category><category>forms</category><category>html</category><category>text</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_book_rules.jpg" length="0" type="image/jpeg"/></item><item><title>How to build Accessible Navigation Menus with the Popover API</title><link>https://www.oidaisdes.org/blog/accessible-navigation-menu</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/accessible-navigation-menu</guid><description>Leveraging the power of modern web features, you can quickly create awesome navigation menus.</description><pubDate>Thu, 17 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://www.w3.org/WAI/tutorials/menus/&quot;&gt;Navigation menus&lt;/a&gt; are an essential part of every website. They’re usually
placed in the header and provide an overview of a website’s page hierarchy. They enable users to gain an overview of
the content and to quickly navigate to main sections of the website.&lt;/p&gt;
&lt;p&gt;Many websites use fly-out (or drop-down) menus, where certain menu items open submenus on hover or click. Often, these
menus offer very poor accessibility for screen reader and keyboard users. But we can do better!&lt;/p&gt;
&lt;p&gt;I’ll show you how to leverage the power of modern web features like the
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Popover_API&quot;&gt;Popover API&lt;/a&gt; to easily create an accessible fly-out menu.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-valentinantonucci-compass.j3Ledd_M_ktfQM.webp&quot; srcset=&quot;/_astro/pexels-valentinantonucci-compass.j3Ledd_M_ZoukWc.webp 640w, /_astro/pexels-valentinantonucci-compass.j3Ledd_M_nKovY.webp 750w, /_astro/pexels-valentinantonucci-compass.j3Ledd_M_24kiYz.webp 828w, /_astro/pexels-valentinantonucci-compass.j3Ledd_M_26XeTz.webp 1080w, /_astro/pexels-valentinantonucci-compass.j3Ledd_M_Z1wStW7.webp 1280w, /_astro/pexels-valentinantonucci-compass.j3Ledd_M_ktfQM.webp 1600w&quot; alt=&quot;A hand holding up a compass for navigation. A rocky coast with trees is visible in the background.&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1067&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Valentin Antonucci / pexels.com&lt;/p&gt;
&lt;h2 id=&quot;what-we-want-to-achieve&quot;&gt;What we want to achieve&lt;/h2&gt;
&lt;p&gt;Our navigation menu should be easy to use for different user groups:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The submenus should appear &lt;strong&gt;on top of the site content&lt;/strong&gt; and should not disappear immediately after
the mouse has left the clickable area.&lt;/li&gt;
&lt;li&gt;Screen reader users require &lt;strong&gt;meaningful markup&lt;/strong&gt; to understand and operate the navigation menu.&lt;/li&gt;
&lt;li&gt;Keyboard users should be able to operate the menu &lt;strong&gt;using the keyboard alone&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;demo-accessible-navigation-menu&quot;&gt;Demo: Accessible Navigation Menu&lt;/h2&gt;
&lt;p&gt;I’ve created a &lt;a href=&quot;https://codepen.io/alexlehner86/full/ExqWMpb&quot;&gt;CodePen demo&lt;/a&gt; of an accessible navigation menu using the
Popover API. Be sure to open the demo on a desktop screen or tablet in landscape mode to see the fly-out menu. On smaller
devices, the demo will display a mobile menu instead.&lt;/p&gt;
&lt;img src=&quot;/_astro/screenshot_accesible_nav_menu.DAYKAu7L_Z20tV3V.webp&quot; srcset=&quot;/_astro/screenshot_accesible_nav_menu.DAYKAu7L_1D9XeT.webp 640w, /_astro/screenshot_accesible_nav_menu.DAYKAu7L_EYIG.webp 750w, /_astro/screenshot_accesible_nav_menu.DAYKAu7L_lCgjY.webp 828w, /_astro/screenshot_accesible_nav_menu.DAYKAu7L_Pfjay.webp 1080w, /_astro/screenshot_accesible_nav_menu.DAYKAu7L_Z20tV3V.webp 1211w&quot; alt=&quot;Screenshot of the accessible navigation menu demo page. The submenu of the menu item solutions is open.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1211px) 1211px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1211&quot; height=&quot;685&quot;&gt;
&lt;p&gt;&lt;em&gt;Photo: © Alexander Lehner&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The navigation menu is easy to use for mouse, keyboard, and screen reader users. Let’s examine the key elements.&lt;/p&gt;
&lt;h3 id=&quot;meaningful-markup&quot;&gt;Meaningful Markup&lt;/h3&gt;
&lt;p&gt;We use the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;nav&lt;/code&gt;  element to convey the role of the navigation menu. The menu items are placed
inside an unordered list (&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;ul&lt;/code&gt;  element). This allows assistive technologies to announce the number
of items in the menu and provide corresponding navigation functionality.&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;nav&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;main-nav&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;            &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; popovertarget&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;nav-panel-solutions&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;button&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Solutions&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;            &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;nav-panel-solutions&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; popover&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; href&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;#&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Products&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;nav&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The list items either contain a direct link to a subpage, or they contain a &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;button&lt;/code&gt;  element
that opens a submenu which uses the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;popover&lt;/code&gt;  attribute. The button is connected to the popover
content via the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;popovertarget&lt;/code&gt;  attribute.&lt;/p&gt;
&lt;p&gt;One of the great advantages of the Popover API: It automatically conveys to assistive technologies whether the
submenu navigation is presently collapsed or expanded. You should read the article
&lt;a href=&quot;https://hidde.blog/popover-accessibility/&quot;&gt;“On popover accessibility: what the browser does and doesn’t do”&lt;/a&gt;
for more information.&lt;/p&gt;
&lt;h3 id=&quot;avoid-the-menu-role&quot;&gt;Avoid the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;menu&lt;/code&gt;  role&lt;/h3&gt;
&lt;p&gt;As you can see in my demo, I’m not using the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;menu&lt;/code&gt;  and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;menuitem&lt;/code&gt;  roles
in my navigation menu. This is on purpose! These ARIA roles are only inteded for menu widgets that behave like native
operating system menus.&lt;/p&gt;
&lt;p&gt;Go read the article &lt;a href=&quot;https://adrianroselli.com/2017/10/dont-use-aria-menu-roles-for-site-nav.html&quot;&gt;“Don’t Use ARIA Menu Roles for Site Nav”&lt;/a&gt;
by Adrian Roselli for a detailed explanation.&lt;/p&gt;
&lt;h3 id=&quot;visual-placement&quot;&gt;Visual Placement&lt;/h3&gt;
&lt;p&gt;When a submenu is opened, it will automatically appear on the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/Top_layer&quot;&gt;top layer&lt;/a&gt;,
a separate layer that sits on top of all other layers displayed in the web document. You only need to take care of the
placement and size of the submenu:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;header&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt; nav.main-nav&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;popover&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    top&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;--header-height&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    margin&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    width&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;100%&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The default placement of popover content is in the center of the screen. To place our submenus right beneath the header,
we set &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;top&lt;/code&gt;  to the height of the header and remove any &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;margin&lt;/code&gt; . Next, we
set &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;width&lt;/code&gt;  to &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;100%&lt;/code&gt;  to make the submenu cover the whole width of the page.&lt;/p&gt;
&lt;h3 id=&quot;keyboard-operability&quot;&gt;Keyboard Operability&lt;/h3&gt;
&lt;p&gt;You can use the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;TAB&lt;/code&gt;  key to focus the links and buttons in the navigation menu. After opening a
submenu, its content will be next in the focus order. Pressing the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;ESC&lt;/code&gt;  key will close the submenu
and automatically return focus to the trigger button. All thanks to the mighty Popover API! 🤩&lt;/p&gt;
&lt;h3 id=&quot;light-dismiss-of-submenus&quot;&gt;Light-dismiss of Submenus&lt;/h3&gt;
&lt;p&gt;Another baked in feature of the Popover API is light-dismiss: Clicking outside of the submenu area will close the submenu
and return focus to the trigger element. No need to mess around with &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;focusout&lt;/code&gt;  events in JavaScript.&lt;/p&gt;
&lt;h2 id=&quot;useful-resources&quot;&gt;Useful Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/WAI/tutorials/menus/&quot;&gt;Navigation Menus Tutorial (W3C)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/&quot;&gt;Disclosure Pattern (ARIA APG)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/examples/disclosure-navigation/&quot;&gt;Example Disclosure Navigation Menu (ARIA APG)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Popover_API&quot;&gt;Popover API (MDN)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>accessibility</category><category>css</category><category>html</category><category>navigation</category><category>popover</category><category>popup</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_compass.jpg" length="0" type="image/jpeg"/></item><item><title>Easy Offline Storage with idb and the IndexedDB API</title><link>https://www.oidaisdes.org/blog/offline-storage-indexeddb</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/offline-storage-indexeddb</guid><description>The idb library makes it easy to store data on your device and retrieve it for offline use.</description><pubDate>Mon, 09 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I really like the JavaScript library &lt;a href=&quot;https://www.npmjs.com/package/idb&quot;&gt;idb&lt;/a&gt;, a minimal wrapper for
the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API&quot;&gt;IndexedDB API&lt;/a&gt;. I’ve used it in several
web applications to provide offline capabilities.&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;idb&lt;/code&gt;  library makes it easy to store data on your device and retrieve it later via
a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot;&gt;Promise&lt;/a&gt;. It also
includes great &lt;a href=&quot;https://www.typescriptlang.org/&quot;&gt;TypeScript&lt;/a&gt; types and interfaces that support creating generic
logic for interacting with your offline storage.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-rdne-stock-project-boxes.D6BOtcUl_2pnqwD.webp&quot; srcset=&quot;/_astro/pexels-rdne-stock-project-boxes.D6BOtcUl_2rknVm.webp 640w, /_astro/pexels-rdne-stock-project-boxes.D6BOtcUl_13OqWF.webp 750w, /_astro/pexels-rdne-stock-project-boxes.D6BOtcUl_Z23ti31.webp 828w, /_astro/pexels-rdne-stock-project-boxes.D6BOtcUl_Z23eS1y.webp 1080w, /_astro/pexels-rdne-stock-project-boxes.D6BOtcUl_Z1VqUpP.webp 1280w, /_astro/pexels-rdne-stock-project-boxes.D6BOtcUl_2pnqwD.webp 1600w&quot; alt=&quot;A woman sitting on the floor surrounded by cardboard boxes.&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1067&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © RDNE Stock project / pexels.com&lt;/p&gt;
&lt;p&gt;Let’s take a look at the basics of setting up a database with &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;idb&lt;/code&gt; . Then I’ll
provide some code examples of reusable generic methods for storing and retrieving data.&lt;/p&gt;
&lt;h2 id=&quot;setting-up-the-database&quot;&gt;Setting up the database&lt;/h2&gt;
&lt;p&gt;First of all, you’ll need to define the schema for the data you want to store. Here’s a basic example:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;DBSchema&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;quot;idb&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; interface&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; MyAwesomeDB&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; extends&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; DBSchema&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    images&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        value&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; MyImageData&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        key&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    videos&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        value&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; MyVideoData&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        key&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I recommend you bundle the DB operations in their own class. This class only serves the specific purpose of
interacting with the database, making your code easier to read and understand. In an Angular application,
I would create an &lt;a href=&quot;https://angular.io/guide/architecture-services&quot;&gt;injectable service class&lt;/a&gt; like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;IDBPDatabase&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;openDB&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;quot;idb&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;Injectable&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; OfflineStorageService&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; _databaseVersion&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;    // The promise returned when opening the IndexedDB with openDB() method.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; _myDatabase$&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; Promise&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;IDBPDatabase&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;MyAwesomeDB&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; init&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;_myDatabase$&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; openDB&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;MyAwesomeDB&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;            &amp;quot;my-awesome-database&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;            this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;_databaseVersion&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;            {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;                // Initialize objects in database if opened for the first time.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;                upgrade&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;database&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;oldVersion&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;            },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;        // Handle success and error case.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;_myDatabase$&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;then&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;            () &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; console&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;IndexedDB was successfully opened.&amp;quot;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color:#F44747&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;            () &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;onOpeningDatabaseFailed&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;storing-data&quot;&gt;Storing data&lt;/h2&gt;
&lt;p&gt;Let’s assume you want to store several items in a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/IDBObjectStore&quot;&gt;specific object store&lt;/a&gt;
of your database. Usually, you’ll open a &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;transaction&lt;/code&gt;  with readwrite access and then store
the items. For this operation, you can define a generic method with the parameters &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;storeName&lt;/code&gt; 
and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;items&lt;/code&gt; :&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;StoreNames&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;StoreValue&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;quot;idb&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;// Stores all items in the object store named &amp;quot;storeName&amp;quot;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; storeAllItemsInObjectStore&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;Name&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; extends&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; StoreNames&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;MyAwesomeDB&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;&amp;gt;&amp;gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;storeName&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; Name&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;items&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; StoreValue&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;MyAwesomeDB&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;Name&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;&amp;gt;[])&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;    this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;_myDatabase$&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;?.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;then&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;database&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;        const&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; transaction&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; database&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;transaction&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;storeName&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;readwrite&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        items&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;forEach&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;item&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; transaction&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;store&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;item&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The method uses the types &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;StoreNames&lt;/code&gt;  and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;StoreValue&lt;/code&gt;  from the &lt;span class=&quot;c-italic&quot;&gt;idb library&lt;/span&gt; .
They make sure that the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;storeName&lt;/code&gt;  parameter passed to the method is actually part of the database
and that the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;items&lt;/code&gt;  have the expected data structure. Here’s an example of using this generic method:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; storeImages&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;items&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;MyImageData&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[]): &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;    this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;storeAllItemsInObjectStore&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;images&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;items&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;retrieving-data&quot;&gt;Retrieving data&lt;/h2&gt;
&lt;p&gt;When retrieving data from the local database, I prefer turning the native &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Promise&lt;/code&gt;  into
an &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Observable&lt;/code&gt; . This makes it easier to integrate the offline storage into an observable
based application state logic (e.g., &lt;a href=&quot;https://ngrx.io/&quot;&gt;NgRx store&lt;/a&gt;). Here’s a generic method that returns
a specific item from an object store wrapped in an observable:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;StoreKey&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;StoreNames&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;StoreValue&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;quot;idb&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;Observable&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;catchError&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;switchMap&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;quot;rxjs&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;// Retrieves the item identified via &amp;quot;itemKey&amp;quot; from the object store named &amp;quot;storeName&amp;quot;. Resolves with undefined if no match is found, the database is unavailable, or there&amp;#39;s an error.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; getItemFromObjectStore&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;Name&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; extends&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; StoreNames&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;MyAwesomeDB&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;&amp;gt;&amp;gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    storeName&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; Name&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    itemKey&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; StoreKey&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;MyAwesomeDB&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;Name&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;&amp;gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; Observable&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;StoreValue&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;MyAwesomeDB&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;Name&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; undefined&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;_myDatabase$&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; ===&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; of&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;undefined&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;_myDatabase$&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;pipe&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;        switchMap&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;database&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;database&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;storeName&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;itemKey&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;))),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;        catchError&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            console&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; of&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;undefined&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        }),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can use the generic method like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; getImage&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;imageId&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;): &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;Observable&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;MyImageData&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; undefined&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    return this.getItemFromObjectStore(&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;images&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, imageId);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Have fun using &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;IndexedDB&lt;/code&gt;  and the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;idb&lt;/code&gt;  library!&lt;/p&gt;</content:encoded><category>angular</category><category>database</category><category>javascript</category><category>storage</category><category>typescript</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_cardboard_boxes.jpg" length="0" type="image/jpeg"/></item><item><title>Native Dialogs and the Popover API — What you need to know</title><link>https://www.oidaisdes.org/blog/native-dialog-and-popover</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/native-dialog-and-popover</guid><description>Learn how to animate dialogs and popovers, correctly nest them, and close dialogs on backdrop click.</description><pubDate>Sat, 15 Jun 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The modern web is awesome! We can easily create accessible, robust modal dialogs with the
native &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt;  element. Want to open a menu or tooltip on top of the other page
content? No problem! The HTML attribute &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;popover&lt;/code&gt;  turns any element into popover content.&lt;/p&gt;
&lt;p&gt;The last few months, I’ve been building more and more dialogs with the
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog&quot;&gt;native HTML element&lt;/a&gt;. And in April, when
the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Popover_API&quot;&gt;Popover API&lt;/a&gt; reached cross-browser support,
I started experimenting with popover in various projects. I quickly realized: These web features make our lives
as web developers a lot easier, but there are some pitfalls. Especially when you combine both features!&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-rama-khandkar-pancakes.C-xTiqnN_1tEsns.webp&quot; srcset=&quot;/_astro/pexels-rama-khandkar-pancakes.C-xTiqnN_2lr7ao.webp 640w, /_astro/pexels-rama-khandkar-pancakes.C-xTiqnN_Z1tSbGe.webp 750w, /_astro/pexels-rama-khandkar-pancakes.C-xTiqnN_SzIl2.webp 828w, /_astro/pexels-rama-khandkar-pancakes.C-xTiqnN_Z24dIPh.webp 1080w, /_astro/pexels-rama-khandkar-pancakes.C-xTiqnN_1G02WE.webp 1280w, /_astro/pexels-rama-khandkar-pancakes.C-xTiqnN_1WhTAA.webp 1668w, /_astro/pexels-rama-khandkar-pancakes.C-xTiqnN_QdSox.webp 2048w, /_astro/pexels-rama-khandkar-pancakes.C-xTiqnN_1NyFMT.webp 2560w, /_astro/pexels-rama-khandkar-pancakes.C-xTiqnN_1tEsns.webp 4032w&quot; alt=&quot;Several pancakes stacked on top of each other.&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 4032px) 4032px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;4032&quot; height=&quot;3024&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Rama Khandkar / pexels.com&lt;/p&gt;
&lt;p&gt;I’ll quickly go over the basics of how dialogs and popovers work together. Then I’ll share some of my hard-earned
learnings with you. If you’re not familiar with the features in general, I recommend you read my blog posts
&lt;a href=&quot;/blog/native-dialog-element/&quot;&gt;“Why you should use the Native Dialog Element”&lt;/a&gt; and
&lt;a href=&quot;/blog/popover-api-accessibility/&quot;&gt;“Make your content pop with the Popover API and CSS Anchor Positioning”&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-basics-how-dialog-and-popover-elements-interact&quot;&gt;The Basics: How dialog and popover elements interact&lt;/h2&gt;
&lt;p&gt;When you open a modal dialog with the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;showModal()&lt;/code&gt;  method, the dialog is added to the
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/Top_layer&quot;&gt;top layer&lt;/a&gt; and rendered on top of other page content.
The same happens when you show popover content using the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;showPopover()&lt;/code&gt;  method.&lt;/p&gt;
&lt;p&gt;Now, what happens if an element is already open in the top layer and you add another element to it? The elements are
stacked in the order they are added to the top layer. The last one in always appears on top. You can’t use
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;z-index&lt;/code&gt;  property to change this stacking order. The only thing that matters is, when
an element was added to the top layer.&lt;/p&gt;
&lt;p&gt;To give you an example: A button opens a menu panel as a popover. This menu contains an option that opens a modal
dialog that is rendered on top of the menu panel. This dialog contains a button that opens a tooltip popover on top
of the dialog. We could go on and on. 😉&lt;/p&gt;
&lt;h2 id=&quot;what-you-need-to-know-about-dialogs-and-popovers&quot;&gt;What you need to know about dialogs and popovers&lt;/h2&gt;
&lt;h3 id=&quot;animation-as-progressive-enhancement&quot;&gt;Animation as progressive enhancement&lt;/h3&gt;
&lt;p&gt;Everything looks better with smooth entry and exit animations. There’s only one problem: Dialogs and popovers are set
to &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;display: none&lt;/code&gt;  when hidden and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;display: block&lt;/code&gt;  when shown. And we
all know that you can’t transition content from or to &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;display: none&lt;/code&gt; . Right? Wrong!&lt;/p&gt;
&lt;p&gt;The new &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@starting-style&lt;/code&gt;  rule together with the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;transition-behavior&lt;/code&gt; 
CSS property enable us to animate dialogs and popovers. I described both features in detail in my blog post
&lt;a href=&quot;/blog/accessible-popover-alert/&quot;&gt;“Accessible Alerts made easy by the Popover API”&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Check out my demo for a modal dialog with smooth fade in and out animation. At the moment of writing, this only works
in Chrome and Edge:&lt;/p&gt;
&lt;iframe title=&quot;Dialog Animation Demo&quot; src=&quot;https://codepen.io/alexlehner86/embed/jOoaZRK?default-tab=result&quot; loading=&quot;lazy&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/alexlehner86/pen/jOoaZRK&quot;&gt;
Dialog Animation Demo&lt;/a&gt; by Alexander Lehner (&lt;a href=&quot;https://codepen.io/alexlehner86&quot;&gt;@alexlehner86&lt;/a&gt;)
on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;&lt;/iframe&gt;
&lt;p&gt;You can define transitions for the dialog (or popover) itself as well as its backdrop. Here’s the CSS code for
animating the dialog:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;dialog&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    --duration&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;150ms&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    --start-opacity&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.5&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    --start-scale&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;scale&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.8&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;    /* End values for fade out. */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    opacity&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;--start-opacity&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transform&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;--start-scale&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transition&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        opacity &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;--duration&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;ease-out&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        transform &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;--duration&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;cubic-bezier&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.2&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;        overlay&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;--duration&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) allow-discrete,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        display &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;--duration&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) allow-discrete;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;dialog&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;open&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;    /* End values for fade in; start values for fade out. */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    opacity&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transform&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;scale&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    @starting-style {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;        /* Start values vor fade in. */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        opacity&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;--start-opacity&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        transform&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;--start-scale&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And this is how you animate the dialog’s backdrop:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;/* Styling for backdrop behind the dialog */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;dialog::backdrop&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    background&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;rgb&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; / &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.32&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;    /* End value for fade out. */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    opacity&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transition&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: opacity &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;--duration&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;        overlay&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;--duration&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) allow-discrete,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        display &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;--duration&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) allow-discrete;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;dialog&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;open&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;::backdrop&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;    /* End value for fade in; start value for fade out. */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    opacity&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;/* This starting-style rule cannot be nested inside the above selector because the nesting selector cannot represent pseudo-elements. */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@starting-style&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;    dialog&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;open&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;::backdrop&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;        /* Start value vor fade in. */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        opacity&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But what about browser support? Don’t worry! The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@starting-style&lt;/code&gt;  rule and
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;transition-behavior&lt;/code&gt;  property are perfect examples of progressive enhancement. If a browser
doesn’t support these new features, then it will still render the dialog or popover element, but without the animation.&lt;/p&gt;
&lt;h3 id=&quot;automatically-close-the-dialog-on-backdrop-click&quot;&gt;Automatically close the dialog on backdrop click&lt;/h3&gt;
&lt;p&gt;The native &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt;  element has several great features built in:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When a modal dialog is opened, the browser moves focus to the first interactive element inside of the dialog.&lt;/li&gt;
&lt;li&gt;Closing the modal dialog returns focus to the element that opened the dialog.&lt;/li&gt;
&lt;li&gt;Users can close the modal dialog with the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;ESC&lt;/code&gt;  key.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But one important feature is not supported by default: Automatically closing the dialog when the user clicks on the
backdrop. In my &lt;a href=&quot;/blog/native-dialog-element/&quot;&gt;first blog post about dialogs&lt;/a&gt;, I demonstrated the following custom
implementation of light dismiss: Getting the coordinates of the click and comparing them to the dialog’s rectangle.&lt;/p&gt;
&lt;p&gt;Some time ago, I came across a more elegant solution: You add
a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener&quot;&gt;click event listener&lt;/a&gt; to your dialog
and then check the tag name of the event target. Here’s the JavaScript code for the function:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; onDialogClick&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    event&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;stopPropagation&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;target&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;tagName&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; ===&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;quot;DIALOG&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        dialogElementRef&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;close&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A click on the dialog’s backdrop is registered as a click on the dialog element. For this to work, the dialog’s content
needs to be wrapped in an extra element. Otherwise, clicking inside certain areas in the dialog would also close it.&lt;/p&gt;
&lt;p&gt;Check out the CodePen demo above where I also implemented this custom behavior.&lt;/p&gt;
&lt;h3 id=&quot;how-to-properly-nest-popover-content-in-modal-dialogs&quot;&gt;How to properly nest popover content in modal dialogs&lt;/h3&gt;
&lt;p&gt;Some time ago, I was working on a web project for a client that includes a list of items. The user can click on one of
the items to open a modal dialog with more details. This dialog contains a button that allows the user to add the item
to their list of favorites. Afterwards, a &lt;a href=&quot;https://m3.material.io/components/snackbar/overview&quot;&gt;snackbar&lt;/a&gt;
appears on the bottom of the screen that also includes an undo button.&lt;/p&gt;
&lt;p&gt;Being the hip, state-of-the-art web developer that I am, I wanted to use the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt;  element
combined with a &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;popover&lt;/code&gt;  element for the snackbar. After implementing everything, I started to
test the undo feature and was baffled: Although the snackbar with the undo button was visible and appeared on top of the
modal dialog, I wasn’t able to interact with it. Me: &lt;span class=&quot;c-italic&quot;&gt;“What the hell is happening?!”&lt;/span&gt; &lt;/p&gt;
&lt;p&gt;After some research, I found the cause of the problem. But before I tell you, check out this demo with a minimal version of
the web project I described above. The dialog includes two buttons: The first opens a snackbar that you can’t interact with.
The second button opens a snackbar with a working undo button. Can you tell the difference?&lt;/p&gt;
&lt;iframe title=&quot;Dialog with Popover Demo&quot; src=&quot;https://codepen.io/alexlehner86/embed/mdYqZdW?default-tab=result&quot; loading=&quot;lazy&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/alexlehner86/pen/mdYqZdW&quot;&gt;
Dialog with Popover Demo&lt;/a&gt; by Alexander Lehner (&lt;a href=&quot;https://codepen.io/alexlehner86&quot;&gt;@alexlehner86&lt;/a&gt;)
on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;&lt;/iframe&gt;
&lt;p&gt;Let me explain what’s going on: In general, the position of a &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;popover&lt;/code&gt;  element in the DOM doesn’t
affect its visibility. When you show the popover, the browser adds it to the top layer and it appears on top of all other
content. But only because you can see something doesn’t mean you can interact with it. The answer can be found in the
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement/showModal&quot;&gt;description of the showModal() method&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The showModal() method of the HTMLDialogElement interface displays the dialog as a modal […]. Interaction outside the
dialog is blocked and &lt;strong&gt;the content outside it is rendered inert&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This means, if you place the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;popover&lt;/code&gt;  element for the snackbar outside of the dialog, then it’s
rendered inert. All user input events for the element and its descendants are ignored. So what can you
do? Simply place the popover element inside of the dialog element. Now the browser considers it part of the dialog’s content
and won’t render it inert.&lt;/p&gt;
&lt;h3 id=&quot;always-close-manual-popovers-nested-inside-dialogs&quot;&gt;Always close manual popovers nested inside dialogs&lt;/h3&gt;
&lt;p&gt;One last observation about manual popovers nested inside a modal dialog. If you close the dialog, make sure to also close
the popover with the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;hidePopover()&lt;/code&gt;  method. Otherwise, the popover might not be visible, but would
still be open and remain in the top layer.&lt;/p&gt;
&lt;p&gt;Now, when you open the dialog again, it will be placed above the popover inside the top layer. So even if you try to open
the popover again with the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;showPopover()&lt;/code&gt;  method, nothing will happen! The popover is already open
and placed beneath the modal dialog in the top layer. What a mess!&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The native &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt;  element and the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;popover&lt;/code&gt;  attribute are very
powerful and convenient features. But there are some pitfalls. I hope my learnings can help you to make great use of
these awesome features in your own projects. Happy coding! 😊&lt;/p&gt;
&lt;h2 class=&quot;post-update-title&quot;&gt; &lt;span aria-hidden=&quot;true&quot;&gt;&amp;raquo;&amp;nbsp;&lt;/span&gt;Update on 03/28/2026 &lt;/h2&gt; 
&lt;p&gt;Use the new &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;closedby&lt;/code&gt;  attribute instead of JavaScript to add light dismiss behavior to the dialog.
This feature should have cross-browser support until the end of the year. Learn more in my new article
&lt;a href=&quot;/blog/dialog-closedby-attribute/&quot;&gt;“Enhance Dialogs with the closedby Attribute”&lt;/a&gt;.&lt;/p&gt;</content:encoded><category>accessibility</category><category>animation</category><category>css</category><category>dialog</category><category>html</category><category>popover</category><category>popup</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_pancakes.jpg" length="0" type="image/jpeg"/></item><item><title>Will the CSS Scope Feature replace Angular&apos;s View Encapsulation?</title><link>https://www.oidaisdes.org/blog/css-scope-view-encapsulation</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/css-scope-view-encapsulation</guid><description>Learn how to use native scoping and create code that is easier to read and debug.</description><pubDate>Thu, 02 May 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;We developers love convenience. We welcome any tool or feature that makes our lives easier. This is especially true
in regards to styling web content with CSS.&lt;/p&gt;
&lt;p&gt;One major challenge is to define CSS rules that target specific elements without writing
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity&quot;&gt;overly-specific selectors&lt;/a&gt; that are hard to override.
Also, you don’t want to couple your selectors too tightly to the DOM structure as it is prone to change.&lt;/p&gt;
&lt;p&gt;Various JavaScript frameworks have come up with different solutions for the problem: React uses
&lt;a href=&quot;https://create-react-app.dev/docs/adding-a-css-modules-stylesheet/&quot;&gt;CSS Modules&lt;/a&gt;, which allow the scoping of CSS by
automatically creating a unique class name for a component’s styles. In Angular, a component’s styles are
&lt;a href=&quot;https://angular.io/guide/view-encapsulation&quot;&gt;encapsulated using custom HTML attributes&lt;/a&gt; so that they don’t affect the
rest of the application.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-cottonbro-donuts.CcURM5kp_Zxe2C7.webp&quot; srcset=&quot;/_astro/pexels-cottonbro-donuts.CcURM5kp_fw0Sb.webp 640w, /_astro/pexels-cottonbro-donuts.CcURM5kp_26wuM6.webp 750w, /_astro/pexels-cottonbro-donuts.CcURM5kp_Z14g2U8.webp 828w, /_astro/pexels-cottonbro-donuts.CcURM5kp_AoECN.webp 1080w, /_astro/pexels-cottonbro-donuts.CcURM5kp_ZKm1.webp 1280w, /_astro/pexels-cottonbro-donuts.CcURM5kp_Zxe2C7.webp 1600w&quot; alt=&quot;A box with six donuts in different colors.&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1067&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © cottonbro studio / pexels.com&lt;/p&gt;
&lt;p&gt;But why can’t we scope styles with CSS alone? Actually, we can! The new &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@scope&lt;/code&gt;  CSS at-rule
allows you to scope styles to specific DOM subtrees. You can even define lower bounds for the scope, creating a
so-called &lt;span class=&quot;c-italic&quot;&gt;donut scope&lt;/span&gt; .&lt;/p&gt;
&lt;p&gt;I’ll explain the basics of this new CSS feature and test its capabilities with an Angular demo application.&lt;/p&gt;
&lt;h2 id=&quot;demo-css-scope-vs-view-encapsulation&quot;&gt;Demo: CSS Scope vs View Encapsulation&lt;/h2&gt;
&lt;p&gt;My &lt;a href=&quot;https://github.com/alexlehner86/test-css-scope&quot;&gt;demo application&lt;/a&gt; was generated with Angular 17. It includes a header
and main section with some paragraphs, links, and several recipe cards.&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;app-recipe-card&lt;/code&gt;  component (yellow background) uses the new CSS scope feature to only
target the HTML elements in its own subtree. Important: At the moment of writing this article,
&lt;a href=&quot;https://caniuse.com/css-cascade-scope&quot;&gt;scoped styles only work in Chrome, Edge, and Safari&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;For comparison, I’ve also defined the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;app-recipe-card-old&lt;/code&gt;  component (blue background), which
uses Angular’s default view encapsulation. Go ahead and inspect the elements with your browser’s developer tools.&lt;/p&gt;
&lt;iframe src=&quot;https://alexlehner86.github.io/test-css-scope/&quot; title=&quot;CSS Scope vs View Encapsulation Demo&quot; loading=&quot;lazy&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;As the demo shows, CSS scope enables us to write simple selectors with low specificity and without the need of extra
class names. Let’s take an in-depth look at how it all works.&lt;/p&gt;
&lt;h2 id=&quot;the-basics-of-css-scope&quot;&gt;The Basics of CSS Scope&lt;/h2&gt;
&lt;p&gt;The new CSS scope feature is defined in the &lt;a href=&quot;https://www.w3.org/TR/css-cascade-6/&quot;&gt;CSS Cascading and Inheritance Level 6&lt;/a&gt;
module, which is still a working draft at the time of writing this post. It states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A &lt;strong&gt;scope&lt;/strong&gt; is a subtree or fragment of a document, which can be used by selectors for more targeted matching. A scope is formed by determining: The &lt;strong&gt;scoping root node&lt;/strong&gt;, which acts as the upper bound of the scope, and optionally the &lt;strong&gt;scoping limit elements&lt;/strong&gt;, which act as the lower bounds.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In short, you need to define the root node of the DOM subtree you want to target. Optionally, you can also list one
or more inner elements that represent the lower boundary of your scope.&lt;/p&gt;
&lt;h3 id=&quot;the-scope-css-at-rule&quot;&gt;The @scope CSS at-rule&lt;/h3&gt;
&lt;p&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;app-recipe-card&lt;/code&gt;  component in my demo includes headings, paragraphs, and an unordered list.
We style them with the following CSS code:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@scope&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; (app-recipe-card) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;    h3&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        color&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;--highlight-color&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        font-size&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1.3rem&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;    p&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        margin-block&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 1em&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;    ul&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        list-style&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;square&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        margin&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        padding-inline-start&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1.25rem&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;    li::marker&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        color&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;--highlight-color&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@scope&lt;/code&gt;  block above defines &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;app-recipe-card&lt;/code&gt;  as
the &lt;span class=&quot;c-italic&quot;&gt;scoping root&lt;/span&gt; , which determines the upper boundary of the subtree we want to target.
Now all contained style rules, like &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;h3 { … }&lt;/code&gt; , can only select from that limited subtree
of the DOM.&lt;/p&gt;
&lt;h3 id=&quot;creating-a-donut-scope&quot;&gt;Creating a Donut Scope&lt;/h3&gt;
&lt;p&gt;In some cases, only setting a scoping root won’t be enough. In &lt;a href=&quot;https://angular.io&quot;&gt;Angular&lt;/a&gt; or &lt;a href=&quot;https://react.dev/&quot;&gt;React&lt;/a&gt;,
you usually nest components within other components to create complex user interfaces. How can you make sure that the
parent component’s styles don’t affect its child components?&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@scope&lt;/code&gt;  at-rule also accepts a &lt;span class=&quot;c-italic&quot;&gt;scoping limit&lt;/span&gt;  which determines the
lower boundary. In my demo, the recipe cards are nested within the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;app-recipes-list&lt;/code&gt;  component.
Here’s part of its CSS code:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@scope&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; (app-recipes-list) to (app-recipe-card, app-recipe-card-old) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;    p&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        font-style&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;italic&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This way, we only italicize the paragraphs defined by the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;app-recipes-list&lt;/code&gt;  parent component. The
paragraphs inside the child components &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;app-recipe-card&lt;/code&gt;  and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;app-recipe-card-old&lt;/code&gt; 
are not affected.&lt;/p&gt;
&lt;p&gt;This type of scoping – with an upper and lower boundary – is called a &lt;span class=&quot;c-italic&quot;&gt;donut scope&lt;/span&gt; . I recommend you
also read the article &lt;a href=&quot;https://developer.chrome.com/docs/css-ui/at-scope&quot;&gt;“Limit the reach of your selectors with the CSS @scope at-rule”&lt;/a&gt;
by Bramus Van Damme. It includes great visualizations of different scope scenarios.&lt;/p&gt;
&lt;h3 id=&quot;the-scope-selector&quot;&gt;The :scope selector&lt;/h3&gt;
&lt;p&gt;Another useful feature is the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;:scope&lt;/code&gt;  selector. It allows you to target the scoping root element
itself inside of the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@scope&lt;/code&gt;  block. Here’s an example from my demo:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@scope&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; (app-recipe-card) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;    :scope&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        --highlight-color&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;rgb&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;194&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 34&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        display&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;block&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        background&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;lightgoldenrodyellow&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        color&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;black&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        padding&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1rem&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;browser-support&quot;&gt;Browser Support&lt;/h3&gt;
&lt;p&gt;What’s that? You think that CSS scope is awesome and want to use it right away in all your projects? Unfortunately,
you’ll have to be patient.&lt;/p&gt;
&lt;p&gt;At the moment, the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@scope&lt;/code&gt;  at-rule
is &lt;a href=&quot;https://caniuse.com/css-cascade-scope&quot;&gt;only supported by Chrome 118+, Edge 118+, and Safari 17.4+&lt;/a&gt;.
Firefox doesn’t support it yet, but Mozilla is &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1830512&quot;&gt;actively working on the feature&lt;/a&gt;.
Let’s hope for cross-browser support sometime in 2024!&lt;/p&gt;
&lt;h2 id=&quot;how-to-use-scope-in-an-angular-application&quot;&gt;How to use @scope in an Angular application&lt;/h2&gt;
&lt;p&gt;In Angular, a &lt;a href=&quot;https://angular.io/guide/view-encapsulation&quot;&gt;component’s styles are encapsulated by default&lt;/a&gt;. The framework
creates custom HTML attributes like &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;_ngcontent-pmm-6&lt;/code&gt; , adds them to the generated HTML elements
and modifies the component’s CSS selectors so that they are only applied to the component’s view.&lt;/p&gt;
&lt;p&gt;If you want to use the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@scope&lt;/code&gt;  at-rule instead, you need to manually switch off view encapsulation
for each component.&lt;/p&gt;
&lt;h3 id=&quot;switching-off-view-encapsulation&quot;&gt;Switching Off View Encapsulation&lt;/h3&gt;
&lt;p&gt;To disable view encapsulation, you need to set &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;encapsulation&lt;/code&gt;  to &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;ViewEncapsulation.None&lt;/code&gt; 
in the &lt;a href=&quot;https://angular.io/api/core/Component&quot;&gt;component’s decorator&lt;/a&gt;. Here’s an example from my demo:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;Component&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    selector:&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;#39;app-recipe-card&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    standalone:&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    templateUrl:&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;#39;./recipe-card.component.html&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    styleUrl:&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;#39;./recipe-card.component.css&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    encapsulation:&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; ViewEncapsulation&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;None&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; RecipeCardComponent&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;Input&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;required:&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; }) &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;recipe&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;!:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; Recipe&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now your CSS selectors won’t be extended with custom attributes and the component styles are applied globally.
You’ll need to use the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@scope&lt;/code&gt;  at-rule instead to encapsulate the styles.&lt;/p&gt;
&lt;h3 id=&quot;comparing-the-html-and-css-output&quot;&gt;Comparing the HTML and CSS output&lt;/h3&gt;
&lt;p&gt;As we’ve seen, using CSS scope requires a little bit of effort when creating a component. Simply using Angular’s default
view encapsulation instead would be more convenient.&lt;/p&gt;
&lt;p&gt;But I would argue that the advantages of CSS scope far exceed this minor inconvenience. Let’s take a look at the HTML and CSS
generated for the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;app-recipe-card&lt;/code&gt;  component in my demo:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;app-recipe-card&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;h3&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Pizza Margherita&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;h3&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;The best pizza in town!&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;h4&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Ingredients&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;h4&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Cutting edge CSS features!&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        /* More list items */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;app-recipe-card&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;/* Generated CSS code (excerpt) */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@scope&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; (app-recipe-card) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;    h3&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        color&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;--highlight-color&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        font-size&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1.3rem&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s compare this to the HTML and CSS generated for the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;app-recipe-card-old&lt;/code&gt;  component:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;app-recipe-card-old&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; _nghost-ng-c2291633987&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;h3&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; _ngcontent-ng-c2291633987&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Pizza Margherita (Old)&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;h3&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; _ngcontent-ng-c2291633987&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;The (second) best pizza in town!&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;h4&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; _ngcontent-ng-c2291633987&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Ingredients&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;h4&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; _ngcontent-ng-c2291633987&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; _ngcontent-ng-c2291633987&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;DOM cluttering view encapsulation&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        /* More list items */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;app-recipe-card-old&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;/* Generated CSS code (excerpt) */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;h3&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;_ngcontent-ng-c2291633987&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    color&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;--highlight-color&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    font-size&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1.3rem&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now imagine you need to debug your application. The recipe card isn’t rendered the way you intended. You open your browser’s
developer tools and inspect the DOM and the applied styles. Which code would be easier to read and understand?&lt;/p&gt;
&lt;p&gt;I think that the myriad of &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;_ngcontent-ng-c2291633987&lt;/code&gt;  attributes would be very distracting. I think
that my mind would find it easier to process the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@scope (app-recipe-card) { h3 }&lt;/code&gt;  selector than
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;h3[_ngcontent-ng-c2291633987]&lt;/code&gt;  selector. 😉&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Getting back to my initial question: Will the CSS scope feature replace Angular’s view encapsulation? Maybe. I really don’t
know. Ideally, the Angular team will adapt their default view encapsulation mechanism to use the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@scope&lt;/code&gt; 
at-rule.&lt;/p&gt;
&lt;p&gt;Regardless of what the Angular team does: It’s already pretty easy to switch off view encapsulation for a component and define
the styles inside a &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@scope&lt;/code&gt;  block. The generated HTML and CSS code has better readability and is far
easier to debug. It also contributes to a reduced bundle size of your web application.&lt;/p&gt;
&lt;p&gt;For me, one thing is certain: As soon as CSS scope has cross-browser support, I’ll be using it in my projects. 🤩&lt;/p&gt;
&lt;h2 class=&quot;post-update-title&quot;&gt; &lt;span aria-hidden=&quot;true&quot;&gt;&amp;raquo;&amp;nbsp;&lt;/span&gt;Update on 02/24/2026 &lt;/h2&gt; 
&lt;p&gt;Native CSS scope has cross-browser support now. Learn more about this awesome feature in my new article
&lt;a href=&quot;/blog/css-scope-angular-best-practices/&quot;&gt;“Best Practices for CSS Scope in Angular Applications”&lt;/a&gt;.&lt;/p&gt;</content:encoded><category>angular</category><category>css</category><category>encapsulation</category><category>react</category><category>scope</category><category>styling</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_donuts.jpg" length="0" type="image/jpeg"/></item><item><title>Support different color themes with a two-color focus indicator</title><link>https://www.oidaisdes.org/blog/two-color-focus-indicator</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/two-color-focus-indicator</guid><description>Create an accessible, universal focus indicator that works in light and dark mode.</description><pubDate>Thu, 21 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Do you use the keyboard to surf the web? If so, then you’ll appreciate having a clearly visible focus indicator.
This accessibility feature is especially important for people with motor impairments who rely on a keyboard, instead
of a mouse, to navigate a web page.&lt;/p&gt;
&lt;p&gt;In general, I recommend using the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;:focus-visible&lt;/code&gt;  pseudo-class to define custom focus
indicators. Check out my article &lt;a href=&quot;/blog/highly-visible-keyboard-focus/&quot;&gt;“Provide highly visible Keyboard Focus with :focus-visible”&lt;/a&gt;
for more information. But how do you account for different color themes and dark mode?&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-cottonbro-keyboard.S0lQaG98_ZWJYFF.webp&quot; srcset=&quot;/_astro/pexels-cottonbro-keyboard.S0lQaG98_ZWudMY.webp 640w, /_astro/pexels-cottonbro-keyboard.S0lQaG98_HnbJ1.webp 750w, /_astro/pexels-cottonbro-keyboard.S0lQaG98_ZlgvEo.webp 828w, /_astro/pexels-cottonbro-keyboard.S0lQaG98_Z27NIX3.webp 1080w, /_astro/pexels-cottonbro-keyboard.S0lQaG98_5c0oj.webp 1280w, /_astro/pexels-cottonbro-keyboard.S0lQaG98_ZWJYFF.webp 1600w&quot; alt=&quot;Closeup of a person&apos;s hands typing on a laptop keyboard.&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1067&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © cottonbro / pexels.com&lt;/p&gt;
&lt;p&gt;The elegant solution is: Define a two-color focus indicator that has sufficient contrast against any solid background
color. The &lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Techniques/css/C40&quot;&gt;W3C’s Technique C40&lt;/a&gt; recommends this solution as a possible
way to conform with the WCAG criteria &lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/focus-visible&quot;&gt;2.4.7: Focus Visible&lt;/a&gt;
and &lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/focus-appearance&quot;&gt;2.4.13: Focus Appearance&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;demo-two-color-focus-indicator&quot;&gt;Demo: Two-Color Focus Indicator&lt;/h2&gt;
&lt;p&gt;Here’s my &lt;a href=&quot;https://codepen.io/alexlehner86/pen/wvZJbBd&quot;&gt;demo&lt;/a&gt; of an accessible two-color focus indicator. You can toggle
between light and dark mode using the checkbox labelled “Dark Mode”. Focus on the button and the link with the tab key and
observe the focus indicator:&lt;/p&gt;
&lt;iframe title=&quot;Two-color focus indicator&quot; src=&quot;https://codepen.io/alexlehner86/embed/wvZJbBd?default-tab=result&quot; loading=&quot;lazy&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/alexlehner86/pen/wvZJbBd&quot;&gt;
Two-color focus indicator&lt;/a&gt; by Alexander Lehner (&lt;a href=&quot;https://codepen.io/alexlehner86&quot;&gt;@alexlehner86&lt;/a&gt;)
on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;&lt;/iframe&gt;
&lt;p&gt;How does this work?&lt;/p&gt;
&lt;h2 id=&quot;the-not-so-secret-css-ingredients&quot;&gt;The (not so) secret CSS ingredients&lt;/h2&gt;
&lt;p&gt;To create the two-color focus indicator, you simply combine the CSS properties &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;outline&lt;/code&gt; 
and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;box-shadow&lt;/code&gt;  to draw a light and dark line around the focused element.&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;:is&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;href&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;], &lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;:focus-visible&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;    /* inner indicator */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    outline&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;3px&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; #fff&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; solid&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    outline-offset&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;    /* outer indicator */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    box-shadow&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 5px&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; #000&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This way, one of the lines always provides sufficient contrast with the current background color. In my demo, I used
a simple combination of pure white and black. But you can also use other colors, as the W3C technique explains:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;As long as the two indicator colors have a &lt;strong&gt;contrast ratio of at least 9:1 with each other&lt;/strong&gt;, at least
one of the two colors is guaranteed to meet 3:1 contrast with any solid background color.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The two-color focus indicator even works in forced colors mode. If you’re not familiar with this feature, then read
my article &lt;a href=&quot;/blog/forced-colors-mode/&quot;&gt;“CSS tweaks for better visibility in Forced Colors Mode”&lt;/a&gt;.&lt;/p&gt;</content:encoded><category>accessibility</category><category>contrast</category><category>css</category><category>design</category><category>keyboard</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_keyboard.jpg" length="0" type="image/jpeg"/></item><item><title>Enhance your Designs with Accessibility Annotations</title><link>https://www.oidaisdes.org/blog/design-a11y-annotations</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/design-a11y-annotations</guid><description>Mark headings, alternative texts, links and buttons in your prototypes.</description><pubDate>Mon, 26 Feb 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Accessibility is a joint project. To ensure that a website is easy to use for all users, accessibility should be
considered throughout the entire development process. How can designers best contribute?&lt;/p&gt;
&lt;p&gt;As a web developer and requirements engineer, I work closely with UI/UX designers. Based on the requirements, they
develop designs and &lt;a href=&quot;https://medium.com/sketch-app-sources/what-is-a-design-prototype-the-complete-guide-f79cce54c50e&quot;&gt;prototypes for the user interface&lt;/a&gt;,
which developers later implement. This work is often very visually dominated: Which colors are used? How do we best
take the customer’s corporate identity into account?&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-amina-filkins-women-tablet.DcIZdccM_IvtbN.webp&quot; srcset=&quot;/_astro/pexels-amina-filkins-women-tablet.DcIZdccM_ZQeMxb.webp 640w, /_astro/pexels-amina-filkins-women-tablet.DcIZdccM_1i9DrM.webp 750w, /_astro/pexels-amina-filkins-women-tablet.DcIZdccM_ZIXHK1.webp 828w, /_astro/pexels-amina-filkins-women-tablet.DcIZdccM_Z282HSm.webp 1080w, /_astro/pexels-amina-filkins-women-tablet.DcIZdccM_ZrNyxk.webp 1280w, /_astro/pexels-amina-filkins-women-tablet.DcIZdccM_IvtbN.webp 1600w&quot; alt=&quot;Two employees of a flower store look at the tablet on the table in front of them.&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1067&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Amina Filkins / pexels.com&lt;/p&gt;
&lt;p&gt;When designers tackle accessibility, they often think of the &lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/use-of-color.html&quot;&gt;use of color&lt;/a&gt;
and &lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum&quot;&gt;sufficient contrast ratios&lt;/a&gt;. But designs can do
even more: accessibility annotations convey important information about the structure and semantics of the website.&lt;/p&gt;
&lt;h2 id=&quot;the-a11y-annotation-kit-for-figma&quot;&gt;The A11y Annotation Kit for Figma&lt;/h2&gt;
&lt;p&gt;There are various programs for creating prototypes. My colleagues like to work with &lt;a href=&quot;https://www.figma.com&quot;&gt;Figma&lt;/a&gt;,
a collaborative platform for UI/UX design.&lt;/p&gt;
&lt;p&gt;To document accessibility considerations there, designers can define suitable elements themselves or work with ready-made
libraries such as the &lt;a href=&quot;https://www.figma.com/community/file/953682768192596304/a11y-annotation-kit&quot;&gt;A11y Annotation Kit&lt;/a&gt;.
This offers a wide range of tools to mark up semantic information in the design. Let’s take a closer look at a few of them.&lt;/p&gt;
&lt;h2 id=&quot;mark-up-headings&quot;&gt;Mark up Headings&lt;/h2&gt;
&lt;p&gt;Sighted users usually scan a website for headings to find what they are looking for. Headings are also of central importance
for blind and visually impaired users: According to the &lt;a href=&quot;https://webaim.org/projects/screenreadersurvey10/#heading&quot;&gt;latest survey by WebAIM&lt;/a&gt;,
9 out of 10 screen reader users say that meaningful heading levels are very or somewhat useful for them.&lt;/p&gt;
&lt;p&gt;Headings must be marked up semantically so that screen readers can recognize them as headings. On websites, this is done with
the HTML tags &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;h1&lt;/code&gt;  to &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;h6&lt;/code&gt; . Users can then use keyboard shortcuts to jump from
heading to heading, for example, and thus get a quick overview.&lt;/p&gt;
&lt;p&gt;Designers should consider as early as possible how the content of a page can be
&lt;a href=&quot;https://www.w3.org/WAI/tutorials/page-structure/headings/&quot;&gt;meaningfully structured with headings&lt;/a&gt;. In the final design, all
headings and their level (1 to 6) should be annotated. Here’s an example:&lt;/p&gt;
&lt;img src=&quot;/_astro/website_a11y_annotation_headings_en.CJ7XkyJo_24aujK.webp&quot; srcset=&quot;/_astro/website_a11y_annotation_headings_en.CJ7XkyJo_2lm5Ar.webp 640w, /_astro/website_a11y_annotation_headings_en.CJ7XkyJo_CxWlq.webp 750w, /_astro/website_a11y_annotation_headings_en.CJ7XkyJo_2qxcsH.webp 828w, /_astro/website_a11y_annotation_headings_en.CJ7XkyJo_Ceylf.webp 1080w, /_astro/website_a11y_annotation_headings_en.CJ7XkyJo_Z2eAqOo.webp 1280w, /_astro/website_a11y_annotation_headings_en.CJ7XkyJo_28Vsbz.webp 1668w, /_astro/website_a11y_annotation_headings_en.CJ7XkyJo_Z1UAc19.webp 2048w, /_astro/website_a11y_annotation_headings_en.CJ7XkyJo_1ObMss.webp 2560w, /_astro/website_a11y_annotation_headings_en.CJ7XkyJo_24aujK.webp 2596w&quot; alt=&quot;A design with two headings marked as h2 and h3.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 2596px) 2596px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;2596&quot; height=&quot;1460&quot;&gt;
&lt;p&gt;&lt;em&gt;Screenshot: © Alexander Lehner&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Two questions will constantly accompany you: What makes a headline a headline? Which headline hierarchy makes sense?
To make your life a little easier, here are a few learnings and tips:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Headings structure the content of the page:&lt;/strong&gt; A heading introduces a new section of content and should describe it.
Large font, bold print or a separate line do not automatically turn a text into a heading!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Never skip a heading level!&lt;/strong&gt; The most important heading should be marked as &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;h1&lt;/code&gt; ,
followed by &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;h2&lt;/code&gt; , &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;h3&lt;/code&gt; , etc. Headings with the same or higher rank start a new section.
Headings with a lower rank start new subsections.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Separate styling and semantics:&lt;/strong&gt; The visual appearance of a heading should never determine which heading level
is used! My advice: Define your own heading classes such
as &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;heading-sm&lt;/code&gt; , &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;heading-md&lt;/code&gt; , &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;heading-lg&lt;/code&gt; , etc.
This allows you to style headings regardless of their position in the hierarchy.&lt;/li&gt;
&lt;li&gt;In some cases, a &lt;a href=&quot;https://www.tpgi.com/the-anatomy-of-visually-hidden/&quot;&gt;visually hidden heading&lt;/a&gt; can also make sense in order to
improve the page structure.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Be creative!&lt;/strong&gt; A perfect heading structure is hard work. Make a draft. Get feedback from outside. Refine your
designs step by step. No one is born a master 😉&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;alternative-text-for-images&quot;&gt;Alternative Text for Images&lt;/h2&gt;
&lt;p&gt;Missing or poor alternative text is one of the most common barriers on websites. According to the
&lt;a href=&quot;https://webaim.org/projects/million/&quot;&gt;WebAIM Million 2023 study&lt;/a&gt;, over one third of the images on popular websites have
missing, questionable, or repetitive alternative text.&lt;/p&gt;
&lt;p&gt;Design prototypes should therefore define alternative texts for image content so that visually conveyed information is also
accessible for screen reader users. You should consider the following points:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Functional images:&lt;/strong&gt; If a button or link only contains an image or icon, the alternative text must describe
the purpose of the element.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Informative images:&lt;/strong&gt; These are images that convey relevant information. Here, the design should specify a
concrete alternative text or at least communicate that a meaningful alternative text must be defined.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Decorative images:&lt;/strong&gt; If images are only intended to embellish the page, then they must be hidden from assistive
technologies. The accessibility annotation can represent this with &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;alt=&amp;quot;&amp;quot;&lt;/code&gt; .&lt;/li&gt;
&lt;/ul&gt;
&lt;img src=&quot;/_astro/website_a11y_annotation_alt_text_en.90qyzNBT_ZjaGkM.webp&quot; srcset=&quot;/_astro/website_a11y_annotation_alt_text_en.90qyzNBT_14iVll.webp 640w, /_astro/website_a11y_annotation_alt_text_en.90qyzNBT_ZDubSF.webp 750w, /_astro/website_a11y_annotation_alt_text_en.90qyzNBT_19u3dB.webp 828w, /_astro/website_a11y_annotation_alt_text_en.90qyzNBT_ujvAI.webp 1080w, /_astro/website_a11y_annotation_alt_text_en.90qyzNBT_Z1dAXVX.webp 1280w, /_astro/website_a11y_annotation_alt_text_en.90qyzNBT_Z1UgdJV.webp 1668w, /_astro/website_a11y_annotation_alt_text_en.90qyzNBT_ZTAJ8I.webp 2048w, /_astro/website_a11y_annotation_alt_text_en.90qyzNBT_ZjaGkM.webp 2277w&quot; alt=&quot;A design with several images for which alternative texts are defined.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 2277px) 2277px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;2277&quot; height=&quot;1281&quot;&gt;
&lt;p&gt;&lt;em&gt;Screenshot: © Alexander Lehner&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You can find more information and some negative examples in my article
&lt;a href=&quot;/blog/how-not-to-use-images/&quot;&gt;“A Picture Says More Than a 1000 Words – Unless You’re Blind!”&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;button-or-link&quot;&gt;Button or Link?&lt;/h2&gt;
&lt;p&gt;Links are underlined. Buttons are clickable boxes. Aren’t they? 🤔&lt;/p&gt;
&lt;p&gt;Visually, links and buttons are often not clearly distinguishable from each other. In some designs, links look like classic
buttons, and vice versa. This is usually not a problem for sighted users: they only need to understand that these elements
are interactive.&lt;/p&gt;
&lt;p&gt;However, the semantic role of the elements is particularly important for assistive technologies. Depending on whether the
screen reader announces an element as a link or a button, users expect different behavior:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Links&lt;/strong&gt; navigate to a new resource, e.g. another website or another section on the same page.
You leave the current context.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Buttons&lt;/strong&gt;, on the other hand, trigger an action in the same context, e.g. a pop-up menu or playing a video.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This means that the appearance is secondary. The function of the element is crucial. I recommend you read the
article &lt;a href=&quot;https://marcysutton.com/links-vs-buttons-in-modern-web-applications&quot;&gt;“Links vs. Buttons in Modern Web Applications”&lt;/a&gt;,
which delves deeper into the topic.&lt;/p&gt;
&lt;p&gt;Dear designers: Mark links and buttons according to their function. And please add a legend to your design that tells developers
to use native elements for this. So &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;a&lt;/code&gt;  for links and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;button&lt;/code&gt;  for buttons. Your
users will love you for it! 🤩&lt;/p&gt;</content:encoded><category>accessibility</category><category>design</category><category>figma</category><category>html</category><category>semantics</category><category>UI</category><category>UX</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_women_tablet.jpg" length="0" type="image/jpeg"/></item><item><title>Accessible Alerts made easy by the Popover API</title><link>https://www.oidaisdes.org/blog/accessible-popover-alert</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/accessible-popover-alert</guid><description>Inform the user of important events without interrupting their current task.</description><pubDate>Sat, 06 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Alerts are a &lt;a href=&quot;https://www.w3.org/WAI/ARIA/apg/patterns/alert/&quot;&gt;common pattern&lt;/a&gt; on the web. They show an important
message in a way that attracts the user’s attention without interrupting the current workflow.
For example: &lt;span class=&quot;c-italic&quot;&gt;“Item was added to your cart”&lt;/span&gt; ,
or &lt;span class=&quot;c-italic&quot;&gt;“Login has failed: Check username/password”&lt;/span&gt; .&lt;/p&gt;
&lt;p&gt;Creating accessible and nicely animated alerts will become a lot easier in the near future, thanks to the new
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Popover_API&quot;&gt;Popover API&lt;/a&gt; and new capabilities of CSS transitions.
I’ve prepared a demo that you can try out.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-thirdman-megaphone.BBPypX9V_Z1WRkFx.webp&quot; srcset=&quot;/_astro/pexels-thirdman-megaphone.BBPypX9V_tA1Q6.webp 640w, /_astro/pexels-thirdman-megaphone.BBPypX9V_29sro6.webp 750w, /_astro/pexels-thirdman-megaphone.BBPypX9V_15NIYG.webp 828w, /_astro/pexels-thirdman-megaphone.BBPypX9V_1Wg3Q1.webp 1080w, /_astro/pexels-thirdman-megaphone.BBPypX9V_ZTUkAy.webp 1280w, /_astro/pexels-thirdman-megaphone.BBPypX9V_Z1WRkFx.webp 1600w&quot; alt=&quot;Man speaking into a megaphone.&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1067&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Thirdman / pexels.com&lt;/p&gt;
&lt;p&gt;If you’re not familiar with the Popover API, go read my article
&lt;a href=&quot;/blog/popover-api-accessibility/&quot;&gt;“Make your content pop with the Popover API and CSS Anchor Positioning”&lt;/a&gt; first.
I won’t repeat the basics of the API and instead focus on the relevant parts of this specific use case.&lt;/p&gt;
&lt;h2 id=&quot;accessible-alerts-demo&quot;&gt;Accessible Alerts Demo&lt;/h2&gt;
&lt;p&gt;Here’s my demo of accessible alerts using the Popover API. You can adapt the message as well as the duration
and position of the alert. Give it a try:&lt;/p&gt;
&lt;iframe src=&quot;https://alexlehner86.github.io/accessible-popover-alert/&quot; title=&quot;Accessible Alerts Demo&quot; loading=&quot;lazy&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;The alert appears above all other elements of the page and is automatically announced by screen readers.
I’ve tested this behavior with &lt;a href=&quot;https://www.freedomscientific.com/products/software/jaws/&quot;&gt;JAWS&lt;/a&gt;,
&lt;a href=&quot;https://www.nvaccess.org/download/&quot;&gt;NVDA&lt;/a&gt;, &lt;a href=&quot;https://support.google.com/accessibility/android/answer/6283677?hl=en&quot;&gt;TalkBack&lt;/a&gt;
and &lt;a href=&quot;https://en.wikipedia.org/wiki/VoiceOver&quot;&gt;VoiceOver&lt;/a&gt;. The alert doesn’t interrupt the user’s current task
and disappears after some time.&lt;/p&gt;
&lt;h2 id=&quot;implementation-details&quot;&gt;Implementation Details&lt;/h2&gt;
&lt;p&gt;Now let’s examine the different building blocks that I used to create the accessible, animated alerts.&lt;/p&gt;
&lt;h3 id=&quot;generating-dynamic-html&quot;&gt;Generating dynamic HTML&lt;/h3&gt;
&lt;p&gt;I’ve implemented an &lt;a href=&quot;https://angular.io/guide/architecture-services&quot;&gt;Angular service&lt;/a&gt; that dynamically generates
the popover element using JavaScript methods like &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;createElement()&lt;/code&gt; 
and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;appendChild()&lt;/code&gt; . Check out the &lt;a href=&quot;https://github.com/alexlehner86/accessible-popover-alert/blob/main/src/app/services/alert.service.ts&quot;&gt;demo code&lt;/a&gt;
for more details. You don’t need to be familiar with the Angular framework to understand the important parts.&lt;/p&gt;
&lt;p&gt;The following HTML code is appended to a container at the end of the body element:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; popover&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;manual&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;alert&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;alert top-right&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    This is a very important message&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;popover&lt;/code&gt;  attribute turns the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;div&lt;/code&gt;  element into a popover that
is initially hidden by the browser. We show the popover alert by calling the element’s
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/showPopover&quot;&gt;showPopover() method&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Setting &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;popover=“manual”&lt;/code&gt;  on the element defines a manual popover state. This prevents
light-dismiss, meaning, interacting with other elements on the page won’t close the popover. We close the popover
programmatically using the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/hidePopover&quot;&gt;hidePopover() method&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;semantic-markup&quot;&gt;Semantic Markup&lt;/h3&gt;
&lt;p&gt;Set &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;role=“alert”&lt;/code&gt;  on the popover element to define it as an alert. The document
&lt;a href=&quot;https://www.w3.org/TR/wai-aria-1.2/#alert&quot;&gt;Accessible Rich Internet Applications (WAI-ARIA) 1.2&lt;/a&gt;
describes the alert role as follows:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A type of &lt;strong&gt;live region&lt;/strong&gt; with important, and usually time-sensitive, information. […] Alerts are assertive live regions, which means &lt;strong&gt;they cause immediate notification&lt;/strong&gt; for assistive technology users.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In general, we use &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions&quot;&gt;ARIA live regions&lt;/a&gt;
to communicate dynamic content changes. Setting &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;role=“alert”&lt;/code&gt;  is actually equivalent to
setting &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;aria-live=“assertive”&lt;/code&gt;  and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;aria-atomic=“true”&lt;/code&gt; . This means, as
soon as our popover alert is displayed, screen readers immediately announce the alert’s message.&lt;/p&gt;
&lt;h3 id=&quot;animation&quot;&gt;Animation&lt;/h3&gt;
&lt;p&gt;Now let’s put the icing on the cake. Let’s add some animation to the popover element. There’s only one problem: Popovers
are initially hidden via &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;display: none&lt;/code&gt; . What a nightmare! This creates two obstacles:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;An element with the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;display&lt;/code&gt;  property value of &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;none&lt;/code&gt;  is not rendered.
Therefore, it has no computed values for the different CSS properties like, e.g., &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;opacity&lt;/code&gt; . If there
is no computed value, you have no starting point for the transition.&lt;/li&gt;
&lt;li&gt;The same problem exists the other way around: When the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;display&lt;/code&gt;  property is set to &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;none&lt;/code&gt; ,
it immediately takes the element out of the flow of the rendered HTML document without triggering the transition effect.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Lucky for us, the &lt;a href=&quot;https://drafts.csswg.org/css-transitions-2/&quot;&gt;CSS Transitions Level 2&lt;/a&gt; specification adds new capabilities
to CSS transitions. It defines the new &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@starting-style&lt;/code&gt;  rule:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;strong&gt;@starting-style rule&lt;/strong&gt; is a grouping rule. The style rules inside it are used to establish styles to
transition from, if the previous style change event did not establish a before-change style for the element whose styles are
being computed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This allows us to define a starting state for our transition when the display type changes from &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;none&lt;/code&gt; 
to another type.&lt;/p&gt;
&lt;p&gt;The second piece of the puzzle is the new &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;transition-behavior&lt;/code&gt;  property and
its &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;allow-discrete&lt;/code&gt;  value:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;strong&gt;transition-behavior&lt;/strong&gt; property specifies whether transitions will be started or not for discrete properties.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Discrete properties have values that can’t be interpolated. This is the case, e.g., for the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/display&quot;&gt;display&lt;/a&gt;
and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/overlay&quot;&gt;overlay&lt;/a&gt; properties. To allow transitions for them, we need to
set the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;allow-discrete&lt;/code&gt;  value. You can also include
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;transition-behavior&lt;/code&gt;  value as part of a shorthand &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;transition&lt;/code&gt;  declaration.&lt;/p&gt;
&lt;p&gt;How does it all fit together? My demo includes the “top-right” position, where the alert fades in and slides in from the right.
Here’s the CSS code for the transition:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;.alert&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;popover&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;.top-right&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;    /* Final state of the exit animation */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    opacity&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transform&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;translateX&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;100%&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transition&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: opacity &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.5s&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        transform &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.5s&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;        overlay&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 0.5s&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; allow-discrete,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        display &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.5s&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; allow-discrete;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;.alert&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;popover&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;.top-right&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;popover-open&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;    /* Final state of the show animation */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    opacity&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transform&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;translateX&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;/* Needs to be after the previous [popover]:popover-open rule to take effect, as the specificity is the same */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@starting-style&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;    .alert&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;popover&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;.top-right&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;popover-open&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        opacity&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        transform&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;translateX&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;100%&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the example above, the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;opacity&lt;/code&gt;  and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;transform&lt;/code&gt;  properties
are transitioned for a duration of half a second. We want the browser to show the transitioned content and keep the
popover in the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/Top_layer&quot;&gt;top layer&lt;/a&gt; for the entire animation duration.
To achieve this, we also include &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;overlay 0.5s allow-discrete&lt;/code&gt; 
and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;display 0.5s allow-discrete&lt;/code&gt;  in the transition.&lt;/p&gt;
&lt;p&gt;Warning: These features are experimental and might change in the future!&lt;/p&gt;
&lt;h2 id=&quot;browser-support&quot;&gt;Browser Support&lt;/h2&gt;
&lt;p&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;popover&lt;/code&gt;  attribute is already &lt;a href=&quot;https://caniuse.com/mdn-api_htmlelement_popover&quot;&gt;supported in all major browsers&lt;/a&gt;.
At the time of writing this article, Firefox had only enabled the feature in its experimental Nightly builds. But I expect
Firefox to release the feature soon.&lt;/p&gt;
&lt;p&gt;The new transition capabilities are only supported by &lt;a href=&quot;https://caniuse.com/mdn-css_properties_transition-behavior&quot;&gt;Chrome and Edge&lt;/a&gt;
at the moment. I’m hopeful that they’ll be part of &lt;a href=&quot;https://github.com/web-platform-tests/interop/tree/main/2024&quot;&gt;Interop 2024&lt;/a&gt;
and reach cross-browser compatibility until the end of the year.&lt;/p&gt;
&lt;h2 id=&quot;useful-resources&quot;&gt;Useful Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/WAI/ARIA/apg/patterns/alert/&quot;&gt;Alert Pattern (ARIA Authoring Practices Guide)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Popover_API&quot;&gt;Popover API (MDN)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://drafts.csswg.org/css-transitions-2/&quot;&gt;CSS Transitions Level 2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>accessibility</category><category>angular</category><category>animation</category><category>css</category><category>html</category><category>popover</category><category>popup</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_megaphone2.jpg" length="0" type="image/jpeg"/></item><item><title>The PDF Accessibility Checker: Strengths and Weaknesses</title><link>https://www.oidaisdes.org/blog/pdf-accessibility-checker</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/pdf-accessibility-checker</guid><description>The tool detects major accessibility violations. But it does not replace manual testing.</description><pubDate>Wed, 06 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;From invoices for online shopping to official notices: PDF documents are ubiquitous today. Numerous companies
and organizations use the file format to display and exchange information. But are PDFs also accessible?
The short answer: It depends!&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-antoni-shkraba-document.gEzVoALd_bKUuH.webp&quot; srcset=&quot;/_astro/pexels-antoni-shkraba-document.gEzVoALd_28pK1s.webp 640w, /_astro/pexels-antoni-shkraba-document.gEzVoALd_ZCpzgU.webp 750w, /_astro/pexels-antoni-shkraba-document.gEzVoALd_ZC2MjM.webp 828w, /_astro/pexels-antoni-shkraba-document.gEzVoALd_2p76X2.webp 1080w, /_astro/pexels-antoni-shkraba-document.gEzVoALd_Z1BPbi1.webp 1280w, /_astro/pexels-antoni-shkraba-document.gEzVoALd_bKUuH.webp 1600w&quot; alt=&quot;A document with text blocks and graphics.&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1067&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © ANTONI SHKRABA production / pexels.com&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://en.wikipedia.org/wiki/PDF/UA&quot;&gt;PDF/UA&lt;/a&gt; standard was published in 2012. It defines how a PDF document
can meet accessibility requirements. Unfortunately, even today many documents do not comply with this standard.&lt;/p&gt;
&lt;p&gt;To prevent this from happening to you, you should check your PDFs for accessibility. The audit is best started with
the &lt;strong&gt;PDF Accessibility Checker&lt;/strong&gt;, or PAC for short. This free standard tool has recently been
released in version 2024: &lt;a href=&quot;https://pac.pdf-accessibility.org/en&quot;&gt;https://pac.pdf-accessibility.org/en&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I have been using the tool for several years now and appreciate its strengths. However, the automated tool does not
replace a manual check, for example with a screen reader and keyboard. I will therefore give you a brief overview of
the strengths and weaknesses of the PDF Accessibility Checker.&lt;/p&gt;
&lt;h2 id=&quot;the-tools-strengths&quot;&gt;The tool’s strengths&lt;/h2&gt;
&lt;p&gt;The PAC is a tool for automatically checking PDF documents for accessibility in accordance with the PDF/UA standard
(DIN/ISO 14289-1). In addition, relevant points of the &lt;span class=&quot;c-italic&quot;&gt;Web Content Accessibility Guidelines (WCAG)&lt;/span&gt; 
and additional quality features are checked.&lt;/p&gt;
&lt;img src=&quot;/_astro/screenshot-pac-2024-details.DvnYDDOz_Z1TxCk0.webp&quot; srcset=&quot;/_astro/screenshot-pac-2024-details.DvnYDDOz_Z1GDlhy.webp 640w, /_astro/screenshot-pac-2024-details.DvnYDDOz_Zl1ahW.webp 750w, /_astro/screenshot-pac-2024-details.DvnYDDOz_lDAIx.webp 828w, /_astro/screenshot-pac-2024-details.DvnYDDOz_Z1Vkpy2.webp 1080w, /_astro/screenshot-pac-2024-details.DvnYDDOz_x0fMA.webp 1280w, /_astro/screenshot-pac-2024-details.DvnYDDOz_Z1TxCk0.webp 1536w&quot; alt=&quot;Result of the accessibility check of a PDF document with the PAC 2024.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1536px) 1536px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1536&quot; height=&quot;1012&quot;&gt;
&lt;p&gt;The PAC can automatically detect the following barriers, among others:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No title is set for the PDF document.&lt;/li&gt;
&lt;li&gt;The language of the document is not defined.&lt;/li&gt;
&lt;li&gt;The contents of the PDF document are not tagged.&lt;/li&gt;
&lt;li&gt;An image does not have an alternative text.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Furthermore, the tool also transparently shows which guidelines it checks and which it does not in the WCAG tab.
Guidelines such as &lt;span class=&quot;c-italic&quot;&gt;“2.1 Keyboard Accessible”&lt;/span&gt;  and &lt;span class=&quot;c-italic&quot;&gt;“3.2 Predictable”&lt;/span&gt; 
can only be checked manually.&lt;/p&gt;
&lt;h2 id=&quot;the-tools-weaknesses&quot;&gt;The tool’s weaknesses&lt;/h2&gt;
&lt;p&gt;The PDF Accessibility Checker can check the code of a PDF document according to certain rules. However, it cannot
understand and interpret the content of the document. Automated checking tools generally cannot do this.&lt;/p&gt;
&lt;p&gt;To show the tool’s weaknesses, I conducted an experiment: How many barriers can I include in a PDF document without
the PAC sounding the alarm? My &lt;a href=&quot;/pdf/pdf_accessibility_test_en.pdf&quot;&gt;test document&lt;/a&gt; consists of several headings, body text
and an image. You can download the document and audit it yourself.&lt;/p&gt;
&lt;p&gt;Let’s now take a closer look at the individual barriers.&lt;/p&gt;
&lt;h3 id=&quot;no-descriptive-title&quot;&gt;No descriptive title&lt;/h3&gt;
&lt;p&gt;My test document has the title &lt;span class=&quot;c-italic&quot;&gt;“A Fabulous Title”&lt;/span&gt; . PAC is satisfied with this. However,
when screen reader users hear this title, they won’t be very happy about it.&lt;/p&gt;
&lt;p&gt;The title of a website or document is the first piece of information that users come across. The title should describe
the content and provide orientation for users. The relevant
&lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/page-titled.html&quot;&gt;WCAG success criterion 2.4.2&lt;/a&gt; states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Web pages have titles that describe topic or purpose.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Therefore, during a manual check, a human must assess whether the set title of the PDF document is meaningful enough.&lt;/p&gt;
&lt;h3 id=&quot;incorrectly-tagged-headings&quot;&gt;Incorrectly tagged headings&lt;/h3&gt;
&lt;p&gt;As PAC correctly states, the entire content of my test document is tagged. This means that for each element in the PDF,
the type of content it represents is defined. This information is essential for screen reader users, among others, in order
to correctly understand the content and quickly navigate through the document.&lt;/p&gt;
&lt;p&gt;However, I have fooled PAC: All headings, such as &lt;span class=&quot;c-italic&quot;&gt;“A fabulous heading”,&lt;/span&gt;  are marked as body text
with the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;P&amp;gt;&lt;/code&gt;  tag. While sighted people can visually recognize the headings as such, this
information is not captured semantically. The
&lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/info-and-relationships.html&quot;&gt;WCAG success criterion 1.3.1&lt;/a&gt; requires:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Information, structure, and relationships conveyed through presentation can be programmatically determined or are
available in text.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Automated tools such as the PAC cannot assess what should be tagged as a heading and what should not. Therefore, a person
should have the PDF document read aloud by a screen reader. In addition, PAC itself also offers the useful screen reader
preview function, which visualizes the tagging structure.&lt;/p&gt;
&lt;img src=&quot;/_astro/screenshot-pac-2024-test-pdf.E-FqPNgp_ZhxVSN.webp&quot; srcset=&quot;/_astro/screenshot-pac-2024-test-pdf.E-FqPNgp_Z1SrN8L.webp 640w, /_astro/screenshot-pac-2024-test-pdf.E-FqPNgp_Z1ShUiC.webp 750w, /_astro/screenshot-pac-2024-test-pdf.E-FqPNgp_1mYc10.webp 828w, /_astro/screenshot-pac-2024-test-pdf.E-FqPNgp_25Kcus.webp 1080w, /_astro/screenshot-pac-2024-test-pdf.E-FqPNgp_Z1QHm1u.webp 1280w, /_astro/screenshot-pac-2024-test-pdf.E-FqPNgp_ZPH0RG.webp 1668w, /_astro/screenshot-pac-2024-test-pdf.E-FqPNgp_ZhxVSN.webp 1813w&quot; alt=&quot;Comparison of the screen reader preview with the visual presentation of the test document.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1813px) 1813px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1813&quot; height=&quot;1008&quot;&gt;
&lt;h3 id=&quot;no-meaningful-sequence&quot;&gt;No meaningful sequence&lt;/h3&gt;
&lt;p&gt;Take another close look at the screenshot above. Do you notice anything? Exactly, the image is visually in a different
position than in the screen reader preview.&lt;/p&gt;
&lt;p&gt;The reading order is saved separately in a tagged PDF. This allows a logical reading order to be defined, especially for
documents with complex layouts. For example, when blind users navigate through the document with a screen reader, the
virtual cursor of the screen reader follows this sequence.&lt;/p&gt;
&lt;p&gt;Therefore, &lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/meaningful-sequence.html&quot;&gt;WCAG success criterion 1.3.2&lt;/a&gt; defines
the following accessibility requirement:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When the sequence in which content is presented affects its meaning, a correct reading sequence can be programmatically
determined.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;During a manual check, a person with an activated screen reader should therefore navigate sequentially through the document
and consider whether the sequence of content makes sense. The visual presentation serves as a guideline here. However, a
different reading order may also be meaningful.&lt;/p&gt;
&lt;h3 id=&quot;alternative-text-does-not-describe-the-image&quot;&gt;Alternative text does not describe the image&lt;/h3&gt;
&lt;p&gt;The PDF Accessibility Checker only checks images to see whether they are tagged correctly and whether an alternative text
is defined. However, the &lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/non-text-content.html&quot;&gt;WCAG success criterion 1.1.1&lt;/a&gt;
requires more:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;All non-text content that is presented to the user has a text alternative that serves the equivalent purpose, except for
the situations listed below. […]&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The picture in my test document shows the blue, open sea off the coast of Mallorca. The alternative text of the image,
however, reads &lt;span class=&quot;c-italic&quot;&gt;“A dust-dry desert”&lt;/span&gt; . An automated tool cannot recognize that this is nonsense.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The &lt;strong&gt;PDF Accessibility Checker&lt;/strong&gt; is a great tool for auditing a PDF document for major violations. However,
it does not replace manual testing. A comprehensive accessibility audit should include both automated and manual steps.&lt;/p&gt;
&lt;p&gt;PS: Also test the &lt;a href=&quot;/pdf/pdf_accessibility_test_en_corr.pdf&quot;&gt;corrected version of my test document&lt;/a&gt; with a screen reader
to experience the improved user experience for yourself.&lt;/p&gt;</content:encoded><category>accessibility</category><category>documents</category><category>pdf</category><category>tags</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_document_with_charts.jpg" length="0" type="image/jpeg"/></item><item><title>How To Meet WCAG 2.2 — Some Practical Examples</title><link>https://www.oidaisdes.org/blog/how-to-meet-wcag-2-2</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/how-to-meet-wcag-2-2</guid><description>A quick overview of the new success criteria and some practical examples for specific use cases.</description><pubDate>Tue, 17 Oct 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The new version 2.2 of the &lt;span class=&quot;c-italic&quot;&gt;Web Content Accessibility Guidelines&lt;/span&gt;  was released recently.
It adds 9 new success criteria and removes the old &lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/parsing.html&quot;&gt;4.1.1 Parsing&lt;/a&gt;
criterion.&lt;/p&gt;
&lt;p&gt;I won’t bore you with another &lt;span class=&quot;c-italic&quot;&gt;“WCAG 2.2 is finally here!”&lt;/span&gt;  article. Other accessibility experts with
more experience than me have already explained the changes compared to WCAG 2.1 (see the link section at the end). Instead,
I’d like to focus on some of the new criteria and give you practical examples of how to meet them.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-george-milton-hiding-behind-book.3VEi1jrR_E7qNa.webp&quot; srcset=&quot;/_astro/pexels-george-milton-hiding-behind-book.3VEi1jrR_Z2jyY7k.webp 640w, /_astro/pexels-george-milton-hiding-behind-book.3VEi1jrR_Oa5l8.webp 750w, /_astro/pexels-george-milton-hiding-behind-book.3VEi1jrR_108Qwq.webp 828w, /_astro/pexels-george-milton-hiding-behind-book.3VEi1jrR_Z1xfqfJ.webp 1080w, /_astro/pexels-george-milton-hiding-behind-book.3VEi1jrR_Z2lJSPC.webp 1280w, /_astro/pexels-george-milton-hiding-behind-book.3VEi1jrR_E7qNa.webp 1600w&quot; alt=&quot;A woman&apos;s face partially hidden behind a book with a green cover.&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1067&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © George Milton / pexels.com&lt;/p&gt;
&lt;h2 id=&quot;the-new-criteria-of-wcag-22&quot;&gt;The New Criteria of WCAG 2.2&lt;/h2&gt;
&lt;p&gt;Several new criteria aim to improve the operability of websites and apps: Focus indicators should be clearly perceivable and the
focused control should not be obscured by other content on the page.&lt;/p&gt;
&lt;p&gt;Controls should be large enough so they can be easily activated without accidentally activating an adjacent target. If a site has
functionality that uses a dragging movement for operation, then it must offer an alternative way for mouse and keyboard users.&lt;/p&gt;
&lt;p&gt;Here’s a list of all new success criteria that relate to operability:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/focus-not-obscured-minimum.html&quot;&gt;2.4.11 Focus Not Obscured (Minimum) (AA)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/focus-not-obscured-enhanced.html&quot;&gt;2.4.12 Focus Not Obscured (Enhanced) (AAA)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/focus-appearance.html&quot;&gt;2.4.13 Focus Appearance (AAA)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/dragging-movements.html&quot;&gt;2.5.7 Dragging Movements (AA)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/target-size-minimum.html&quot;&gt;2.5.8 Target Size (Minimum) (AA)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The following success criteria aim to improve accessibility for people with cognitive and learning disabilities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/consistent-help.html&quot;&gt;3.2.6 Consistent Help (A)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/redundant-entry.html&quot;&gt;3.3.7 Redundant Entry (A)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/accessible-authentication-minimum.html&quot;&gt;3.3.8 Accessible Authentication (Minimum) (AA)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/accessible-authentication-enhanced.html&quot;&gt;3.3.9 Accessible Authentication (Enhanced) (AAA)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now let’s look at some practical examples for the new success criteria.&lt;/p&gt;
&lt;h2 id=&quot;practical-examples&quot;&gt;Practical Examples&lt;/h2&gt;
&lt;h3 id=&quot;use-case-sticky-page-header&quot;&gt;Use Case: Sticky Page Header&lt;/h3&gt;
&lt;p&gt;Many websites include a header that sticks to the top of the page, even when the page is scrolled. If done right, this sticky header
improves the usability of the website. Imagine a user reading a long article: When they arrive at the bottom of the page, they don’t
have to scroll back up to access the main navigation in the header.&lt;/p&gt;
&lt;p&gt;Unfortunately, a sticky header can hurt the experience of sighted people who can’t use a mouse. When they navigate a website using
the keyboard, they always need to see what has keyboard focus. A sticky header or footer can lead to focused elements disappearing
behind these elements.&lt;/p&gt;
&lt;p&gt;Lucky for us, there’s a simple and elegant solution for this problem: The CSS property &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;scroll-padding&lt;/code&gt;  enables
us to define offsets for the optimal viewing region of the scrollport — the region used as the target region for placing things in view
of the user. All you need is one line of CSS:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    scroll-padding&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;4rem&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here’s a demo of a website with a sticky header and footer. Try navigating with the tab key and pay attention to the browser keeping
the focused link in view:&lt;/p&gt;
&lt;iframe src=&quot;https://alexlehner86.github.io/fancy-css-playground/#/scrollpadding&quot; title=&quot;Scroll Padding Demo&quot; loading=&quot;lazy&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;This way, the website conforms to &lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/focus-not-obscured-minimum.html&quot;&gt;2.4.11 Focus Not Obscured (Minimum) (AA)&lt;/a&gt;
and &lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/focus-not-obscured-enhanced.html&quot;&gt;2.4.12 Focus Not Obscured (Enhanced) (AAA)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Another related CSS property is &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;scroll-margin&lt;/code&gt; . You can use it to, e.g., un-obscure content underneath a
fixed-position banner, as the WCAG technique C43 demonstrates:
&lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Techniques/css/C43&quot;&gt;“Using CSS margin and scroll-margin to un-obscure content”&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;use-case-interactive-map-with-drag-to-move&quot;&gt;Use Case: Interactive Map with Drag to Move&lt;/h3&gt;
&lt;p&gt;An interactive map usually allows the user to drag the view of the map with the mouse or on touch. But some people cannot perform
dragging movements in a precise manner. Or they use a specialized input device, such as a trackball, or head pointer, which may make
dragging cumbersome and error-prone.&lt;/p&gt;
&lt;p&gt;An accessible map should also include up/down/left/right buttons to move the view, and conform to the success criterion
&lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/dragging-movements.html&quot;&gt;2.5.7 Dragging Movements (AA)&lt;/a&gt;. Users with motor impairments can
easily tab to the controls and use them to pan the map. Check out my &lt;a href=&quot;https://alexlehner86.github.io/cascade-layers-angular-demo/&quot;&gt;demo&lt;/a&gt;
of a map with zoom and pan buttons:&lt;/p&gt;
&lt;img src=&quot;/_astro/screenshot-map-with-move-controls.CgWrftFQ_TiFWn.webp&quot; srcset=&quot;/_astro/screenshot-map-with-move-controls.CgWrftFQ_Z24sWCa.webp 640w, /_astro/screenshot-map-with-move-controls.CgWrftFQ_2jOr93.webp 750w, /_astro/screenshot-map-with-move-controls.CgWrftFQ_YhVaf.webp 828w, /_astro/screenshot-map-with-move-controls.CgWrftFQ_TiFWn.webp 852w&quot; alt=&quot;Screenshot of an interactive map that has up/down/left/right buttons to move the view.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 852px) 852px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;852&quot; height=&quot;415&quot;&gt;
&lt;p&gt;&lt;em&gt;Photo: © Alexander Lehner&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As the screenshot above shows, the focused button is clearly highlighted with a thick outline and color change. Continue to the next
section to learn more about accessible focus indicators.&lt;/p&gt;
&lt;h3 id=&quot;use-case-clearly-visible-focus-indicators&quot;&gt;Use Case: Clearly Visible Focus Indicators&lt;/h3&gt;
&lt;p&gt;Providing visible focus indicators is a basic feature of accessible websites and apps. The success criterion
&lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/focus-visible.html&quot;&gt;2.4.7 Focus Visible (AA)&lt;/a&gt; states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Any keyboard operable user interface has a mode of operation where the &lt;strong&gt;keyboard focus indicator is visible&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This criterion has been around for almost 15 years, ever since WCAG 2.0 was released. Unfortunately, there’s still lots of
websites with no or barely visible focus indicators. One of the reasons might be that WCAG never normatively defined what “visible”
meant in practice.&lt;/p&gt;
&lt;p&gt;The new sucess criterion &lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/focus-appearance.html&quot;&gt;2.4.13 Focus Appearance (AAA)&lt;/a&gt; finally
defines the minimum dimensions and appearance for focus indicators. They should cover enough space and provide a contrast of at least
3:1 between an element’s focused and unfocused state.&lt;/p&gt;
&lt;p&gt;Often, a client or designer might oppose strong focus indicators for aesthetic reasons. In this case, I recommend the use of
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;:focus-visible&lt;/code&gt;  CSS pseudo-class. It lets you show focus styles only when they are needed (e.g., on
keyboard navigation). Check out my demo that compares &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;:focus&lt;/code&gt;  to &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;:focus-visible&lt;/code&gt; .&lt;/p&gt;
&lt;iframe src=&quot;https://alexlehner86.github.io/fancy-css-playground/#/a11yfeatures&quot; title=&quot;Demo for the focus-visible pseudo-class&quot; loading=&quot;lazy&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;If you want to go into more details, read my post
&lt;a href=&quot;/blog/highly-visible-keyboard-focus/&quot;&gt;“Provide highly visible Keyboard Focus with :focus-visible”&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;useful-resources&quot;&gt;Useful Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/WCAG22/&quot;&gt;Web Content Accessibility Guidelines (WCAG) 2.2, W3C Recommendation, 05 October 2023&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tetralogical.com/blog/2023/10/05/whats-new-wcag-2.2/&quot;&gt;What’s new in WCAG 2.2 (TetraLogical)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.levelaccess.com/blog/wcag-22-aa-summary-and-checklist-for-website-owners/&quot;&gt;WCAG 2.2 AA: Summary and Checklist for Website Owners (Level Access)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-padding&quot;&gt;MDN: CSS scroll-padding&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible&quot;&gt;MDN: CSS :focus-visible&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>accessibility</category><category>css</category><category>design</category><category>html</category><category>standards</category><category>wcag</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_hiding_behind_book.jpg" length="0" type="image/jpeg"/></item><item><title>Why I think that accessibility certifications are useful</title><link>https://www.oidaisdes.org/blog/pro-accessibility-certifications</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/pro-accessibility-certifications</guid><description>Certifications provide a uniform standard and increase the credibility of experts.</description><pubDate>Thu, 14 Sep 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Accessibility is becoming increasingly important. The &lt;a href=&quot;https://ec.europa.eu/social/main.jsp?catId=1202&quot;&gt;European Accessibility Act&lt;/a&gt;
will prescribe binding requirements for products and services from 2025. This also increases the need for experts who support
companies in the accessible design of their websites and apps.&lt;/p&gt;
&lt;p&gt;But what distinguishes an accessibility expert? How do I know that someone actually has a clue or is just throwing around buzzwords?&lt;/p&gt;
&lt;p&gt;From my point of view, &lt;strong&gt;recognized certifications&lt;/strong&gt; play an important role here. In this article I would like to discuss the
advantages and disadvantages of accessibility certifications and venture a definition of what skills can be expected from
professionals.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-marcus-aurelius-woman-in-wheelchair.CN-B61og_2azenD.webp&quot; srcset=&quot;/_astro/pexels-marcus-aurelius-woman-in-wheelchair.CN-B61og_ZHdqzS.webp 640w, /_astro/pexels-marcus-aurelius-woman-in-wheelchair.CN-B61og_ZSQjVR.webp 750w, /_astro/pexels-marcus-aurelius-woman-in-wheelchair.CN-B61og_c89PQ.webp 828w, /_astro/pexels-marcus-aurelius-woman-in-wheelchair.CN-B61og_XqJ5z.webp 1080w, /_astro/pexels-marcus-aurelius-woman-in-wheelchair.CN-B61og_ZKSnkn.webp 1280w, /_astro/pexels-marcus-aurelius-woman-in-wheelchair.CN-B61og_2azenD.webp 1600w&quot; alt=&quot;A woman in a wheelchair. She balances a laptop on her knees.&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1067&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Marcus Aurelius / pexels.com&lt;/p&gt;
&lt;p&gt;Note: I earned the &lt;a href=&quot;https://www.incite.at/de/programm/certified-webaccessibility-expert/&quot;&gt;“Certified Web Accessibility Expert”&lt;/a&gt;
certificate from UBIT Academy incite in 2019. In the beginning of 2023 I became an “IAAP Certified Professional in Accessibility
Core Competencies (CPACC)” (&lt;a href=&quot;https://www.credly.com/badges/1839d107-b0d4-4788-ac7f-7d4905ed4f7e/linked_in_profile&quot;&gt;credential at Credly&lt;/a&gt;).&lt;/p&gt;
&lt;h2 id=&quot;the-essential-skills-of-an-accessibility-expert&quot;&gt;The Essential Skills of an Accessibility Expert&lt;/h2&gt;
&lt;p&gt;Accessibility experts should have &lt;strong&gt;empathy for people with disabilities&lt;/strong&gt;. They should have a sincere interest in the
everyday life of these people and try to put themselves in their respective situation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How do blind people surf the Internet with the help of a screen reader?&lt;/li&gt;
&lt;li&gt;Under what conditions can people with motor impairments operate a website using the keyboard alone?&lt;/li&gt;
&lt;li&gt;When is video and audio content accessible for deaf people?&lt;/li&gt;
&lt;li&gt;etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;An expert needs to know the &lt;strong&gt;different user groups and assistive technologies&lt;/strong&gt;. These include
&lt;a href=&quot;https://en.wikipedia.org/wiki/Screen_magnifier&quot;&gt;screen magnifiers&lt;/a&gt;, &lt;a href=&quot;/blog/forced-colors-mode/&quot;&gt;high contrast mode&lt;/a&gt;,
&lt;a href=&quot;https://www.youtube.com/watch?v=dEbl5jvLKGQ&quot;&gt;screen readers&lt;/a&gt;,
&lt;a href=&quot;https://www.w3.org/WAI/perspective-videos/voice/&quot;&gt;speech input software&lt;/a&gt;,
&lt;a href=&quot;https://www.w3.org/WAI/perspective-videos/keyboard/&quot;&gt;keyboards&lt;/a&gt;, and many more.&lt;/p&gt;
&lt;p&gt;Knowledge of the relevant &lt;strong&gt;standards and laws&lt;/strong&gt; is another minimum requirement. This includes both the success criteria of
the &lt;a href=&quot;https://www.w3.org/WAI/standards-guidelines/wcag/&quot;&gt;Web Content Accessibility Guidelines (WCAG)&lt;/a&gt;, the European standard
&lt;a href=&quot;https://www.etsi.org/deliver/etsi_en/301500_301599/301549/03.02.01_60/en_301549v030201p.pdf&quot;&gt;EN 301 549&lt;/a&gt;, and relevant national
laws such as the Austrian
&lt;a href=&quot;https://www.usp.gv.at/gesetzliche-neuerungen/Bundesgesetzblatt/barrierefreiheitsgesetz.html&quot;&gt;&lt;span lang=&quot;de&quot;&gt;Barrierefreiheitsgesetz (BaFG)&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In addition, accessibility experts should also have experience in &lt;strong&gt;testing for accessibility&lt;/strong&gt;. They must be able to assess
whether a website or app complies with specific criteria and point out solutions for any barriers found.&lt;/p&gt;
&lt;h2 id=&quot;accessibility-certifications&quot;&gt;Accessibility Certifications&lt;/h2&gt;
&lt;p&gt;Various institutions offer certifications on the topic of accessibility. There are national certification bodies such as the
&lt;a href=&quot;https://www.incite.at/&quot;&gt;UBIT Academy incite&lt;/a&gt; in Austria. They offer certification as
a &lt;span class=&quot;c-italic&quot;&gt;Certified WebAccessibility Expert&lt;/span&gt; .&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.accessibilityassociation.org&quot;&gt;International Association of Accessibility Professionals (IAAP)&lt;/a&gt; offers several
certifications, including the &lt;span class=&quot;c-italic&quot;&gt;Certified Professional in Accessibility Core Competencies (CPACC)&lt;/span&gt;  and
the &lt;span class=&quot;c-italic&quot;&gt;Web Accessibility Specialist (WAS)&lt;/span&gt; . Their aim is to support accessibility experts in building up
their expertise.&lt;/p&gt;
&lt;p&gt;What are the advantages and disadvantages of such certifications?&lt;/p&gt;
&lt;h3 id=&quot;advantages&quot;&gt;Advantages&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Increased credibility&lt;/strong&gt;: Certification is proof that one has certain skills and experience. This underlines the credibility
of experts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Uniform standard&lt;/strong&gt;: In order to obtain certification, interested parties must demonstrate their knowledge of specific
content in examinations or individual interviews. Reputable institutions define a publicly accessible
&lt;a href=&quot;https://www.accessibilityassociation.org/resource/IAAP_CPACC_BOK_March2020&quot;&gt;body of knowledge&lt;/a&gt; for this purpose, which makes
this content transparent.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Community of practice and knowledge exchange&lt;/strong&gt;: IAAP supports the networking of accessibility experts with online forums,
webinars and various events.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;disadvantages&quot;&gt;Disadvantages&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cost&lt;/strong&gt;: Certification is not free. CPACC, for example, costs just under $500 (slightly less for members). Not everyone
can afford it. However, compared to many other certifications in the IT field, I find the price very moderate.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cognitive barrier&lt;/strong&gt;: Often a certification consists of a multiple-choice test with countless questions. For example,
on the CPACC, you have to answer a full 100 questions in two hours. That’s exhausting. For people with cognitive impairment,
that can also be an insurmountable barrier.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;From my point of view, accessibility certifications are a good thing. They provide uniform, transparent proof of concrete
skills. They help companies to distinguish real experts from frauds.&lt;/p&gt;
&lt;p&gt;Do all accessibility experts have to be certified? Of course not. There are other ways to prove your expertise. For example,
if you have been designing accessible websites or apps for many years and can show them as references.&lt;/p&gt;
&lt;p&gt;In any case, I am happy about my certifications. They represent key milestones in my career as an accessibility expert.
And &lt;a href=&quot;https://www.credly.com/badges/1839d107-b0d4-4788-ac7f-7d4905ed4f7e/linked_in_profile&quot;&gt;the badge&lt;/a&gt; I earned just looks cool! 😉&lt;/p&gt;
&lt;h2 id=&quot;useful-resources&quot;&gt;Useful Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.accessibilityassociation.org/s/certification&quot;&gt;IAAP: Certification Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.incite.at/de/programm/certified-webaccessibility-expert/&quot;&gt;Certified WebAccessibility Expert (Austria)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.edx.org/learn/web-accessibility/the-world-wide-web-consortium-w3c-introduction-to-web-accessibility&quot;&gt;W3C: Introduction to Web Accessibility&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>accessibility</category><category>certification</category><category>experts</category><category>iaap</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_woman_in_wheelchair.jpg" length="0" type="image/jpeg"/></item><item><title>Manage concurrent and interdependent requests with RxJS</title><link>https://www.oidaisdes.org/blog/rxjs-concurrent-request-sequence</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/rxjs-concurrent-request-sequence</guid><description>The RxJS library offers powerful operators that will make your dev life a lot easier.</description><pubDate>Sun, 20 Aug 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Have you ever had to retrieve information from multiple data sources or different API endpoints? Did you optimize
your request sequence for &lt;a href=&quot;https://en.wikipedia.org/wiki/Concurrency_(computer_science)&quot;&gt;concurrency&lt;/a&gt; and
interdependent data?&lt;/p&gt;
&lt;p&gt;If you answered yes to at least one of these questions, you should read on now. I’ll show you my solution using
the &lt;a href=&quot;https://angular.io/&quot;&gt;Angular framework&lt;/a&gt; and &lt;a href=&quot;https://www.npmjs.com/package/rxjs&quot;&gt;RxJS&lt;/a&gt;. Let your requests flow
like a series of interconnected waterfalls.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-quang-nguyen-vinh-waterfalls.BwiKyWRI_1Bt72X.webp&quot; srcset=&quot;/_astro/pexels-quang-nguyen-vinh-waterfalls.BwiKyWRI_ZeDcEo.webp 640w, /_astro/pexels-quang-nguyen-vinh-waterfalls.BwiKyWRI_1kegvB.webp 750w, /_astro/pexels-quang-nguyen-vinh-waterfalls.BwiKyWRI_ZIhvm2.webp 828w, /_astro/pexels-quang-nguyen-vinh-waterfalls.BwiKyWRI_Z2bEfuK.webp 1080w, /_astro/pexels-quang-nguyen-vinh-waterfalls.BwiKyWRI_Z2kHSBY.webp 1280w, /_astro/pexels-quang-nguyen-vinh-waterfalls.BwiKyWRI_1Bt72X.webp 1600w&quot; alt=&quot;A series of waterfalls flowing down a rocky slope.&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1067&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Quang Nguyen Vinh / pexels.com&lt;/p&gt;
&lt;p&gt;Before we take an in-depth look at some code examples, here’s a brief explanation of RxJS.&lt;/p&gt;
&lt;h2 id=&quot;what-is-rxjs-and-what-are-observables&quot;&gt;What is RxJS and what are Observables?&lt;/h2&gt;
&lt;p&gt;The name RxJS is an abbreviation for &lt;span class=&quot;c-italic&quot;&gt;Reactive Extensions Library for JavaScript&lt;/span&gt; . In the
official &lt;a href=&quot;https://rxjs.dev/guide/overview&quot;&gt;RxJS Introduction&lt;/a&gt; it says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;RxJS is a library for composing asynchronous and event-based programs by using &lt;strong&gt;observable sequences&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The term “observable sequence” is key here. It represents the idea of an invokable collection of future values. The related
functionality is encapsulated in the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Observable&lt;/code&gt;  class.&lt;/p&gt;
&lt;p&gt;For example, you can create an observable that emits the value of a text input on every value change. Or, you can wrap
the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot;&gt;Promise&lt;/a&gt; of
a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch&quot;&gt;fetch request&lt;/a&gt; in an observable that emits the
response when the promise completes.&lt;/p&gt;
&lt;p&gt;Another key concept to keep in mind is the use of a &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;pipe&lt;/code&gt; . Using an
observable’s &lt;a href=&quot;https://rxjs.dev/api/index/function/pipe&quot;&gt;pipe function&lt;/a&gt;, we can execute a series of actions on the observable
and its datastream. If you’re new to RxJS, you should learn the basics with the official docs. I can also recommend the
website &lt;a href=&quot;https://www.learnrxjs.io/&quot;&gt;Learn RxJS&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-challenge&quot;&gt;The Challenge&lt;/h2&gt;
&lt;p&gt;In a current client project, I was faced with the following challenge: The web application should enable users to make
specific data sets available offline. As a first step, I turned the app into
a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps&quot;&gt;Progressive web app&lt;/a&gt; and created
an &lt;a href=&quot;https://angular.io/guide/creating-injectable-service&quot;&gt;injectable service&lt;/a&gt; that handles the data storage
with &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/IndexedDB&quot;&gt;IndexedDB&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Then I was lost for a moment!&lt;/p&gt;
&lt;p&gt;To be honest: I’ve never had to retrieve information from different API endpoints where the result of some initial requests
would determine hundreds of follow-up requests. I had to optimize the request sequence for concurrency as well as interdependency.&lt;/p&gt;
&lt;p&gt;After a lot of online research and some trial and error, I arrived at a satisfying solution. The following source code is an
adapted version of my client project, which I’m happy to share with you.&lt;/p&gt;
&lt;h2 id=&quot;the-solution&quot;&gt;The Solution&lt;/h2&gt;
&lt;p&gt;Do you like going to the movies? Imagine a web application that shows the movie program for different cinemas. You can see when
which movie is playing, access information about the actors, watch film clips and browse through screenshots. You can also read
general information about the cinemas (e.g. name, location) and their movie halls (e.g., number of seats).&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-pixabay-popcorn.PJrHTrk2_ZuMqQj.webp&quot; srcset=&quot;/_astro/pexels-pixabay-popcorn.PJrHTrk2_ZJlpUA.webp 640w, /_astro/pexels-pixabay-popcorn.PJrHTrk2_gg3tj.webp 750w, /_astro/pexels-pixabay-popcorn.PJrHTrk2_nHbsP.webp 828w, /_astro/pexels-pixabay-popcorn.PJrHTrk2_Z23gquu.webp 1080w, /_astro/pexels-pixabay-popcorn.PJrHTrk2_Z3PznB.webp 1280w, /_astro/pexels-pixabay-popcorn.PJrHTrk2_ZuMqQj.webp 1600w&quot; alt=&quot;Several bags of popcorn.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1200&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Pixabay / pexels.com&lt;/p&gt;
&lt;p&gt;To retrieve and store all this data offline, we need to access different endpoints. Some of the requests (e.g., for each movie)
depend on information retrieved in other requests (e.g., for the movie program). This means, we first need to define a logical
order for our download sequence.&lt;/p&gt;
&lt;h3 id=&quot;step-1-the-main-download-pipe&quot;&gt;Step 1: The Main Download Pipe&lt;/h3&gt;
&lt;p&gt;In my project, the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;CinemaDownloadService&lt;/code&gt;  class contains the entire download logic. The service can be
injected by, e.g., an &lt;a href=&quot;https://angular.io/api/core/Component&quot;&gt;Angular component&lt;/a&gt;. It provides the public
method &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;downloadCinemaInfo&lt;/code&gt;  that downloads all necessary information to make a cinema and its
movie program available offline:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; downloadCinemaInfo&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;cinemaId&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;number&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;): &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;Observable&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;CinemaOfflineData&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    return this.downloadDataForCinemaId(cinemaId).pipe(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;        switchMap&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(this.downloadMovies),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;        switchMap&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(this.downloadActorBiographies),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;        switchMap&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(this.downloadFilmClips),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;        switchMap&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(this.downloadScreenshots),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The method returns an observable that emits the data collection &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;CinemaOfflineData&lt;/code&gt;  once all individual
downloads have finished.&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; interface&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; CinemaOfflineData&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    generalInfo&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; CinemaGeneralInfo&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    movieHalls&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; MovieHall&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    movieProgram&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; MovieProgram&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    movies&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; Movie&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    actorBios&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; Actor&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    filmClips&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; FilmClip&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    screenshots&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; MovieScreenshot&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To collect the data, the method first downloads all information that directly depends on &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;cinemaId&lt;/code&gt; . We’ll
take a closer look at this in a moment. Afterwards, it uses a &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;pipe&lt;/code&gt;  and the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;switchMap&lt;/code&gt; 
operator to download the remaining data.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://rxjs.dev/api/index/function/switchMap&quot;&gt;switchMap operator&lt;/a&gt; takes the value emitted by the observable to create a new
observable, which replaces the old one. To put it in simpler terms: Once we’re finished with a specific download operation, we start a
new one that incorporates the result of the previous operation.&lt;/p&gt;
&lt;h3 id=&quot;step-2-download-basic-information&quot;&gt;Step 2: Download Basic Information&lt;/h3&gt;
&lt;p&gt;As a first step, we want to download the general information about the cinema, its movie halls and the current movie program:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; downloadDataForCinemaId&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;cinemaId&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;number&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;): &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;Observable&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;CinemaOfflineData&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    return &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;forkJoin&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;([&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;_request&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;getCinemaGeneralInfo&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;cinemaId&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;pipe&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            retryStrategy&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        ),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;_request&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;getMovieHalls&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;cinemaId&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;pipe&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            retryStrategy&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        ),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;_request&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;getMovieProgram&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;cinemaId&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;pipe&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            retryStrategy&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        ),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    ]).&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;pipe&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        map&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(([&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;generalInfo&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;movieHalls&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;movieProgram&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;CinemaGeneralInfo&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;MovieHall&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[], &lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;MovieProgram&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;]) &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;            const&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; data&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; CinemaOfflineData&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;                generalInfo&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;movieHalls&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;movieProgram&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;                movies:&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; [], &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;actorBios:&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; [],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;                filmClips:&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; [], &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;screenshots:&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; [],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;            };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; data&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The individual backend requests are made through an independent &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;RequestService&lt;/code&gt; , which we access
through &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;this._request&lt;/code&gt; . The details of the implementation are irrelevant for this post. All you need to know is:
Each request method returns an observable that emits the response and then completes.&lt;/p&gt;
&lt;p&gt;We use the &lt;a href=&quot;https://rxjs.dev/api/index/function/forkJoin&quot;&gt;forkJoin operator&lt;/a&gt; to wait for all requests to finish and then create the
first instance of our &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;CinemaOfflineData&lt;/code&gt;  object. The remaining properties, like &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;movies&lt;/code&gt; ,
are initialized as empty arrays. We’ll download the corresponding
data in the next steps of our download pipe.&lt;/p&gt;
&lt;h3 id=&quot;step-3-limit-concurrent-requests-with-mergemap&quot;&gt;Step 3: Limit Concurrent Requests with &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;mergeMap&lt;/code&gt; &lt;/h3&gt;
&lt;p&gt;After we’ve successfully downloaded the movie program, we want to retrieve all movies that are listed in the program. Depending on
the size of the cinema and the covered time period, this could mean hundreds of individual requests.&lt;/p&gt;
&lt;p&gt;The modern &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/HTTP_2&quot;&gt;HTTP/2 protocol&lt;/a&gt; supports full request multiplexing. But
depending on your backend server and the &lt;a href=&quot;https://medium.com/geekculture/how-to-calculate-server-max-requests-per-second-38a39bb96a85&quot;&gt;maximum requests per second&lt;/a&gt;,
it might be a good idea to limit the number of concurrent requests.&lt;/p&gt;
&lt;p&gt;To achieve this, we use a combination of the following RxJS functions: &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;from&lt;/code&gt; , &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;mergeMap&lt;/code&gt; ,
and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;reduce&lt;/code&gt; . Here’s the complete movies download method:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; downloadMovies&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; CinemaOfflineData&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; Observable&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;CinemaOfflineData&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; movies&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; Movie&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; [];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; movieIds&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;getMovieIds&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;movieProgram&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;movieIds&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;pipe&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;        mergeMap&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            id&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;_request&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;getMovieInfo&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;pipe&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;               retryStrategy&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;            ),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            MAX_CONCURRENT_BACKEND_REQUESTS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        ),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;        reduce&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;            (&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;accumulator&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;item&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;                accumulator&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;push&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;item&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;                return&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; accumulator&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;            },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            movies&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        ),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;        map&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;movies&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; ({ &lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;movies&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; }))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I know, that’s a lot to take in. Let’s look at the implementation step by step:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We extract the unique &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;movieIds&lt;/code&gt;  from the movie program we’ve already downloaded. Then we
use &lt;a href=&quot;https://rxjs.dev/api/index/function/from&quot;&gt;from&lt;/a&gt; to turn the array of movie IDs into an observable.&lt;/li&gt;
&lt;li&gt;Next, we use &lt;a href=&quot;https://rxjs.dev/api/index/function/mergeMap&quot;&gt;mergeMap&lt;/a&gt; to create a request for each movie. We pass the
constant &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;MAX_CONCURRENT_BACKEND_REQUESTS&lt;/code&gt;  as the second parameter to limit the max number of concurrent
requests.&lt;/li&gt;
&lt;li&gt;Each individual request observable applies the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;retryStrategy&lt;/code&gt;  operator to repeat the request in
case it should throw an error. This is my own custom operator, which uses the &lt;a href=&quot;https://rxjs.dev/api/index/function/retry&quot;&gt;retry function&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The next element in our observable pipe is &lt;a href=&quot;https://rxjs.dev/api/index/function/reduce&quot;&gt;reduce&lt;/a&gt;. We use this function to
accumulate the results of all backend requests into a single &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;movies&lt;/code&gt;  array.&lt;/li&gt;
&lt;li&gt;Last, we integrate the movies data into a new instance of our &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;CinemaOfflineData&lt;/code&gt;  object, using
the &lt;a href=&quot;https://rxjs.dev/api/index/function/map&quot;&gt;map operator&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now the main download pipe can move on the the next step: Downloading the biographies for all actors. We extract the
unique &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;actorIds&lt;/code&gt;  from the movies array and apply the same download logic as before:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; downloadActorBiographies&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; CinemaOfflineData&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; Observable&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;CinemaOfflineData&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; actorBios&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; Actor&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; [];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; actorIds&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;getActorIds&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;movies&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;actorIds&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;pipe&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;        mergeMap&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            id&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;_request&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;getActorBiography&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;pipe&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;                retryStrategy&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;            ),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            MAX_CONCURRENT_BACKEND_REQUESTS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        ),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;        reduce&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;            (&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;accumulator&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;item&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;                accumulator&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;push&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;item&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;                return&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; accumulator&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;            },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            actorBios&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        ),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;        map&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;actorBios&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; ({ &lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;actorBios&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; }))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We repeat the same steps for the film clips and the &lt;strong&gt;screenshots&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;step-4-subscribe-to-the-download-observable&quot;&gt;Step 4: Subscribe to the Download Observable&lt;/h3&gt;
&lt;p&gt;To execute the whole download logic, you need to call the public method &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;downloadCinemaInfo&lt;/code&gt;  and
subscribe to the observable it returns:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;_cinemaDownloadService&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;downloadCinemaInfo&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;cinemaId&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    .&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;subscribe&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;cinemaData&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; CinemaOfflineData&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;        /* Store data offline, e.g., with IndexedDB */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    });&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s it! You’ve successfully created an elegant download logic that is optimized for concurrency and interdependent data.&lt;/p&gt;
&lt;p&gt;Of course, you’ll also want to cover error handling using &lt;a href=&quot;https://rxjs.dev/api/index/function/catchError&quot;&gt;catchError&lt;/a&gt;. You might
also want to visualize the download process using a &lt;a href=&quot;https://rxjs.dev/api/index/class/Subject&quot;&gt;Subject&lt;/a&gt; to communicate the
current status.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;As we’ve seen, RxJS offers a set of powerful tools like &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;mergeMap&lt;/code&gt;  and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;reduce&lt;/code&gt; .
They help us to create efficient and robust solutions.&lt;/p&gt;
&lt;p&gt;You can define a main download pipe that provides a quick overview of the individual steps. Then you place the specific
download logic into isolated private functions. This helps to keep your code clean and maintainable.&lt;/p&gt;
&lt;h2 id=&quot;useful-resources&quot;&gt;Useful Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://rxjs.dev/&quot;&gt;RxJS (Reactive Extensions Library for JavaScript)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.learnrxjs.io/&quot;&gt;Learn RxJS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://netbasal.com/creating-custom-operators-in-rxjs-32f052d69457&quot;&gt;Creating Custom Operators in RxJS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>angular</category><category>api</category><category>backend</category><category>http</category><category>javascript</category><category>observables</category><category>rxjs</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_waterfalls.jpg" length="0" type="image/jpeg"/></item><item><title>Make your content pop with the Popover API and CSS Anchor Positioning</title><link>https://www.oidaisdes.org/blog/popover-api-accessibility</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/popover-api-accessibility</guid><description>Building accessible menus, tooltips, and date pickers has never been this easy.</description><pubDate>Sun, 09 Jul 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Menus, tooltips, date pickers, or dialogs – popover content is everywhere on the web. Despite how common these
components are, there are no native HTML elements for most of them (except for &lt;a href=&quot;/blog/native-dialog-element/&quot;&gt;dialogs&lt;/a&gt;).
And their implementation requires quite a lot of JavaScript.&lt;/p&gt;
&lt;p&gt;All of this will change with the new &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Popover_API&quot;&gt;Popover API&lt;/a&gt;
combined with &lt;a href=&quot;https://www.w3.org/TR/css-anchor-position-1/&quot;&gt;CSS Anchor Positioning&lt;/a&gt;. They provide developers with a
powerful mechanism for displaying popover content on top of other page content.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-zachary-debottis-skateboarder-jump.s-LpGV1f_14UB5b.webp&quot; srcset=&quot;/_astro/pexels-zachary-debottis-skateboarder-jump.s-LpGV1f_utH8m.webp 640w, /_astro/pexels-zachary-debottis-skateboarder-jump.s-LpGV1f_Z2tTReH.webp 750w, /_astro/pexels-zachary-debottis-skateboarder-jump.s-LpGV1f_1uFmq9.webp 828w, /_astro/pexels-zachary-debottis-skateboarder-jump.s-LpGV1f_Z1WCApy.webp 1080w, /_astro/pexels-zachary-debottis-skateboarder-jump.s-LpGV1f_ZTSXNp.webp 1280w, /_astro/pexels-zachary-debottis-skateboarder-jump.s-LpGV1f_14UB5b.webp 1600w&quot; alt=&quot;A skateboarder in mid air jump.&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1007&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Zachary DeBottis / pexels.com&lt;/p&gt;
&lt;p&gt;I’ve prepared two demos with examples of popover content. We’ll take an in-depth look at the technical aspects as
well as the accessibility of the new features.&lt;/p&gt;
&lt;h2 id=&quot;what-can-we-do-with-it&quot;&gt;What can we do with it?&lt;/h2&gt;
&lt;p&gt;I love the saying: Show, don’t tell! That’s why I’ve created two demos to illustrate the capabilities of the new API.&lt;/p&gt;
&lt;p&gt;At the moment, the examples only work in &lt;a href=&quot;https://www.google.com/intl/en/chrome/canary/&quot;&gt;Chrome Canary&lt;/a&gt;, the nightly build
for developers. Open the browser and access the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;chrome://flags&lt;/code&gt;  page to enable the experimental web
platform features.&lt;/p&gt;
&lt;p&gt;Warning: The anchor positioning feature is still highly experimental. Therefore, the demos might break
if the specification changes.&lt;/p&gt;
&lt;h3 id=&quot;example-1-custom-tooltip&quot;&gt;Example 1: Custom Tooltip&lt;/h3&gt;
&lt;p&gt;Standard tooltips created with the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;title&lt;/code&gt;  attribute are pretty bland. So, I’ve tried my hand at
a fancy &lt;a href=&quot;https://codepen.io/alexlehner86/pen/dyQRJBv&quot;&gt;custom tooltip&lt;/a&gt;. Click on the info icon button next to the heading:&lt;/p&gt;
&lt;iframe title=&quot;Accessible Tooltip with Popover API&quot; src=&quot;https://codepen.io/alexlehner86/embed/dyQRJBv?default-tab=result&quot; loading=&quot;lazy&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/alexlehner86/pen/dyQRJBv&quot;&gt;
Accessible Tooltip with Popover API&lt;/a&gt; by Alexander Lehner (&lt;a href=&quot;https://codepen.io/alexlehner86&quot;&gt;@alexlehner86&lt;/a&gt;)
on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;&lt;/iframe&gt;
&lt;p&gt;I did my best to make the tooltip accessible, following the &lt;a href=&quot;https://www.w3.org/WAI/ARIA/apg/patterns/tooltip/&quot;&gt;Tooltip Pattern&lt;/a&gt;
defined in the ARIA Authoring Practices Guide. Unfortunately, the desing pattern is still work in progress and there’s no
consensus yet. Also, the Popover API doesn’t account for hover and focus yet.&lt;/p&gt;
&lt;h3 id=&quot;example-2-menu-with-a-set-of-actions&quot;&gt;Example 2: Menu with a Set of Actions&lt;/h3&gt;
&lt;p&gt;I also created a &lt;a href=&quot;https://codepen.io/alexlehner86/pen/rNQmERq&quot;&gt;demo&lt;/a&gt; for an accessible menu. Each item in the list of checked out
books contains a menu button that toggles a menu panel with a set of actions for each book:&lt;/p&gt;
&lt;iframe title=&quot;Accessible Menu with Popover API&quot; src=&quot;https://codepen.io/alexlehner86/embed/rNQmERq?default-tab=result&quot; loading=&quot;lazy&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/alexlehner86/pen/rNQmERq&quot;&gt;
Accessible Menu with Popover API&lt;/a&gt; by Alexander Lehner (&lt;a href=&quot;https://codepen.io/alexlehner86&quot;&gt;@alexlehner86&lt;/a&gt;)
on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;&lt;/iframe&gt;
&lt;p&gt;My implementation follows the &lt;a href=&quot;https://www.w3.org/WAI/ARIA/apg/patterns/menubar/&quot;&gt;Menu and Menubar Pattern&lt;/a&gt; defined in the ARIA
Authoring Practices Guide. I’ve used the appropriate ARIA roles and properties and also implemented (most of) the recommended
keyboard interaction.&lt;/p&gt;
&lt;p&gt;Now let’s examine the different building blocks that I used to create these components.&lt;/p&gt;
&lt;h2 id=&quot;the-magical-popover-attribute&quot;&gt;The magical &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;popover&lt;/code&gt;  attribute&lt;/h2&gt;
&lt;p&gt;This HTML attribute turns any element into popover content. The
&lt;a href=&quot;https://html.spec.whatwg.org/multipage/popover.html#the-popover-attribute&quot;&gt;HTML specification&lt;/a&gt; states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;All HTML elements may have the &lt;strong&gt;popover&lt;/strong&gt; content attribute set. When specified, the element won’t be
rendered until it becomes shown, at which point it will be rendered on top of other page content.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This popover content is always non-modal, meaning that the rest of the page can be interacted with while the popover is open.
If you need to display a modal popover (e.g., a confirmation dialog), you should use the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt; 
element.&lt;/p&gt;
&lt;h2 id=&quot;how-to-create-a-popover&quot;&gt;How to create a popover&lt;/h2&gt;
&lt;p&gt;To create a popover, you add the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;popover&lt;/code&gt;  attribute to an element and also define
an &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;id&lt;/code&gt; . Next, you use the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;popovertarget&lt;/code&gt;  attribute with the value of the
popover’s id on the element that opens the popover. Here’s an example:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; popovertarget&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;popover-1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    Info&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;popover-1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; popover&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    Hi, I&amp;#39;m a popover!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s it! You just created a popover with a few lines of HTML and zero JavaScript. Awesome!&lt;/p&gt;
&lt;h3 id=&quot;built-in-features-of-the-popover-api&quot;&gt;Built-in features of the Popover API&lt;/h3&gt;
&lt;p&gt;When using the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;popover&lt;/code&gt;  attribute, you’ll get all of the following for free:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Placement in the top layer:&lt;/strong&gt; Popover content will automatically appear on
the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/Top_layer&quot;&gt;top layer&lt;/a&gt;, a separate layer that sits on top of all
other layers displayed in a web document. No more worrying about the DOM order or z-index.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Light-dismiss:&lt;/strong&gt; Clicking outside of the popover area will close the popover and return focus to the
trigger element.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Accessible keyboard interaction:&lt;/strong&gt; When the popover is open, you can hit the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;ESC&lt;/code&gt;  key to
close the popover and return focus to the trigger element.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Semantic relationship:&lt;/strong&gt; Connecting a popover element to a toggle button will also create a semantic relationship
for assistive technologies. Think &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;aria-controls&lt;/code&gt;  and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;aria-expanded&lt;/code&gt; 
per default.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;more-options-and-styling&quot;&gt;More options and styling&lt;/h3&gt;
&lt;p&gt;By default, when you create a popover with a &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;popovertarget&lt;/code&gt; , the trigger button will toggle it open
and closed. Alternatively, you can also set an explicit value for the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;popovertargetaction&lt;/code&gt;  attribute:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;“hide”&lt;/strong&gt;: The button will hide a shown popover. This can be useful if you need a close button inside of the popover.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“show”&lt;/strong&gt;: The button will show a hidden popover.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“toggle”&lt;/strong&gt;: The button will toggle a popover between showing and hidden. This is the default behavior.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Furthermore, the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;popover&lt;/code&gt;  attribute is actually a shortcut for &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;popover=“auto”&lt;/code&gt; .
This standard type of popover will force close other auto popovers. It can be dismissed via light-dismiss or a close button.&lt;/p&gt;
&lt;p&gt;With &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;popover=“manual”&lt;/code&gt;  you can create a manual popover. These popovers don’t close via light-dismiss
and they do not force close any other popovers. They must be closed via an explicit close action. A possible use case for manual
popovers are &lt;a href=&quot;https://m2.material.io/components/snackbars&quot;&gt;alert snackbars&lt;/a&gt; that should be confirmed by the user.&lt;/p&gt;
&lt;p&gt;Popovers also include useful CSS features: The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;::backdrop&lt;/code&gt;  pseudo-element allows effects to be added to
the page content behind the popover. You can use the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;:popover-open&lt;/code&gt;  pseudo-class to style popover
elements when they are showing.&lt;/p&gt;
&lt;h2 id=&quot;css-anchor-positioning&quot;&gt;CSS Anchor Positioning&lt;/h2&gt;
&lt;p&gt;If you’ve made it this far, you might be wondering: What about the position of the popover on the page? To position our popover
content relative to other elements, we actually need another new, experimental feature: Anchor Positioning.&lt;/p&gt;
&lt;p&gt;This feature is defined in the CSS Module &lt;a href=&quot;https://www.w3.org/TR/css-anchor-position-1/&quot;&gt;CSS Anchor Positioning&lt;/a&gt;. Right now, the
document is still a &lt;span class=&quot;c-italic&quot;&gt;“Working Draft”&lt;/span&gt; , but Chrome already offers the feature behind the
experimental web platform features flag. The document states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This specification defines &lt;strong&gt;‘anchor positioning’&lt;/strong&gt;, where a positioned element can size and position itself
relative to one or more “anchor elements” elsewhere on the page.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In my examples above, I’ve used anchor positioning to place the tooltip and the menu panels next to their trigger buttons.
Let’s find out how to set up anchors and use them in our CSS styles.&lt;/p&gt;
&lt;h3 id=&quot;how-to-define-an-anchor-element&quot;&gt;How to define an anchor element&lt;/h3&gt;
&lt;p&gt;There are two different ways to set up anchors. You can turn an HTML element into an anchor by giving it
an &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;id&lt;/code&gt; , and then use the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;anchor&lt;/code&gt;  attribute to tether another element to your
anchor. Here’s an example in combination with a popover:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;toggle-btn-1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; popovertarget&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;popover-1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;toggle-btn&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    Info&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;popover-1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; popover&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; anchor&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;toggle-btn-1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    Hi, I&amp;#39;m a popover!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As an alternative, you can use the CSS property &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;anchor-name&lt;/code&gt;  to set up an anchor. It accepts a
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/dashed-ident&quot;&gt;dashed-ident&lt;/a&gt; value like &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;—toggle-btn&lt;/code&gt; .
Next, you use the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;position-anchor&lt;/code&gt;  property to tether another element to your anchor.&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;button.toggle-btn&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    anchor-name: --toggle-btn;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;popover&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    position-anchor: --toggle-btn;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;position-content-with-the-anchor-function&quot;&gt;Position content with the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;anchor()&lt;/code&gt;  function&lt;/h3&gt;
&lt;p&gt;Alright, so far you’ve set up an HTML element as an anchor and tethered your popover to it. Now you can use
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;anchor()&lt;/code&gt;  function to position the popover. The function has three arguments:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Anchor element&lt;/strong&gt;: This value specifies how to find the anchor element. You can specify an explicit anchor name with
a dashed-ident value. Or, you can omit the value to use the implicit anchor that was defined through
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;anchor&lt;/code&gt;  attribute or the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;position-anchor&lt;/code&gt;  CSS property.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Anchor side&lt;/strong&gt;: This value refers to the position of the corresponding side of the target anchor element. For
example: &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;bottom&lt;/code&gt;  or &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;left&lt;/code&gt; .&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fallback (optional)&lt;/strong&gt;: A length or percentage value that serves as a fallback in case of an invalid anchor function.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here’s an example that shows how to place a tooltip below its toggle button and center the content horizontally:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;tooltip&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;][&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;popover&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    position&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;absolute&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    position-anchor: --toggle-btn;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    top&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: anchor(&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;bottom&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    left&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: anchor(&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;center&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    translate&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;-50%&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The specification includes even more features like the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;anchor-scroll&lt;/code&gt;  property and
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;anchor-size()&lt;/code&gt;  function. But this blog post is already long enough, so I’ll skip them for now.&lt;/p&gt;
&lt;h2 id=&quot;accessibility-of-popovers&quot;&gt;Accessibility of Popovers&lt;/h2&gt;
&lt;p&gt;How accessible are popovers? As my examples above show, you can build user-friendly, accessible components with the new
Popover API. But that doesn’t happen by itself.&lt;/p&gt;
&lt;h3 id=&quot;define-the-appropriate-semantic-role&quot;&gt;Define the appropriate semantic role&lt;/h3&gt;
&lt;p&gt;Using the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;popover&lt;/code&gt;  attribute can definitely help your website’s accessibility. For example, with
the ability to close the popover via the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;ESC&lt;/code&gt;  key. Or, through the semantic relationship between the
toggle button and the popover created by the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;popovertarget&lt;/code&gt;  attribute.&lt;/p&gt;
&lt;p&gt;On the other hand, the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;popover&lt;/code&gt;  attribute doesn’t define any implicit role for the HTML element it
is used on. This means, you’ll have to think about your specific use case and choose the correct native HTML element or
assign the appropriate &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles&quot;&gt;ARIA role&lt;/a&gt;
(like &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;tooltip&lt;/code&gt;  or &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;menu&lt;/code&gt; ) yourself.&lt;/p&gt;
&lt;h3 id=&quot;screen-reader-support&quot;&gt;Screen Reader Support&lt;/h3&gt;
&lt;p&gt;How do screen reader users experience the interaction with web content built with the Popover API? Due to the limited
browser support for the new feature, I only tested my demos with the following scenarios:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nvaccess.org/download/&quot;&gt;NVDA&lt;/a&gt; 2023.1, Windows 11, Google Chrome Chanary 117.0.5876.0&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://support.google.com/accessibility/android/topic/10601571?hl=en&quot;&gt;TalkBack&lt;/a&gt;, Samsung Galaxy S20, Android 13,
Google Chrome Chanary 117.0.5876.0&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Both demos worked great: I was able to navigate the tooltip and menus with the keyboard while NVDA
announced the semantic roles and current status of the controls.&lt;/p&gt;
&lt;p&gt;The interaction on my smartphone was also smooth: With TalkBack activated, I navigated the pages using
&lt;a href=&quot;https://support.google.com/accessibility/android/answer/6006598?hl=en&quot;&gt;swipe gestures&lt;/a&gt; while the screen reader informed
me about the content, semantic roles and current status of the controls.&lt;/p&gt;
&lt;p&gt;This makes me really optimistic about the future of the web! I plan on doing more tests with other browsers and
screen readers as soon as the Popover API has better support.&lt;/p&gt;
&lt;h2 id=&quot;browser-support&quot;&gt;Browser Support&lt;/h2&gt;
&lt;p&gt;When can we start using the Popover API and CSS Anchor Positioning in production? Unfortunately, it’s going to take some
time until we have cross-browser support for them.&lt;/p&gt;
&lt;p&gt;According to &lt;a href=&quot;https://caniuse.com/mdn-api_htmlelement_popover&quot;&gt;caniuse.com&lt;/a&gt;, the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;popover&lt;/code&gt;  attribute
is already supported by Chrome and Edge. The &lt;a href=&quot;https://developer.apple.com/documentation/safari-technology-preview-release-notes/stp-release-170&quot;&gt;Safari 17 Technology Preview&lt;/a&gt;
promises support for the attribute and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Experimental_features&quot;&gt;Firefox&lt;/a&gt;
lists it as an experimental feature (behind the flag &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;dom.element.popover.enabled&lt;/code&gt; ).&lt;/p&gt;
&lt;p&gt;Cross-browser support for &lt;a href=&quot;https://www.w3.org/TR/css-anchor-position-1/&quot;&gt;CSS Anchor Positioning&lt;/a&gt; will take even longer. As far
as I know, only Chrome has implemented the experimental feature so far. Because of the status as
a &lt;span class=&quot;c-italic&quot;&gt;“First Public Working Draft”&lt;/span&gt; , the current specification is subject to change in the future.
We’ll just have to wait and see, I guess.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The new Popover API combined with CSS Anchor Positioning will make our lives as web developers easier and help to
make the web more accessible by default.&lt;/p&gt;
&lt;p&gt;Despite the still experimental status of the new APIs, you should play around with them and familiarize yourselves with the
new attributes and properties. This way, when cross-browser support arrives, you’ll be ready to rumble! 😎&lt;/p&gt;
&lt;h2 id=&quot;useful-resources&quot;&gt;Useful Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Popover_API&quot;&gt;Popover API (MDN)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://html.spec.whatwg.org/multipage/popover.html#the-popover-attribute&quot;&gt;HTML specification for the popover attribute&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://open-ui.org/components/popover.research.explainer/&quot;&gt;Popover API Explainer (Open UI)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/css-anchor-position-1/&quot;&gt;CSS Anchor Positioning (Draft)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 class=&quot;post-update-title&quot;&gt; &lt;span aria-hidden=&quot;true&quot;&gt;&amp;raquo;&amp;nbsp;&lt;/span&gt;Update on 04/05/2024 &lt;/h2&gt; 
&lt;p&gt;Revised code examples and explanations to account for changed CSS Anchor Positioning specification
(W3C Working Draft, 26 March 2024) and the implementation in Chrome Canary.&lt;/p&gt;
&lt;h2 class=&quot;post-update-title&quot;&gt; &lt;span aria-hidden=&quot;true&quot;&gt;&amp;raquo;&amp;nbsp;&lt;/span&gt;Update on 04/18/2025 &lt;/h2&gt; 
&lt;p&gt;CSS Anchor Positioning is part of &lt;a href=&quot;https://wpt.fyi/interop-2025&quot;&gt;Interop 2025&lt;/a&gt;. That’s why I’m
fairly certain that we’ll have cross-browser support until the end of the year.&lt;/p&gt;</content:encoded><category>accessibility</category><category>css</category><category>html</category><category>keyboard</category><category>popover</category><category>popup</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_skateboarder_jump.jpg" length="0" type="image/jpeg"/></item><item><title>Unleash the Power of Inline SVG Images</title><link>https://www.oidaisdes.org/blog/unleash-power-of-inline-svg</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/unleash-power-of-inline-svg</guid><description>An inline SVG image can be easily customized with CSS and is highly flexible.</description><pubDate>Thu, 22 Jun 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;SVG images are an integral part of modern web design. SVG, short for &lt;span class=&quot;c-italic&quot;&gt;Scalable Vector Graphics&lt;/span&gt; ,
are highly scalable and have a small file size. You can also customize them with CSS, as I’ll show you.&lt;/p&gt;
&lt;p&gt;In general, you can embed an SVG image in a website using the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;img&amp;gt;&lt;/code&gt;  tag or the CSS
property &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;background-image&lt;/code&gt; . In this case, you won’t be able to make major style changes to the
image. I prefer to use inline SVG images instead. They can be customized and even animated with CSS.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-andrea-piacquadio-painter.DIvHNElN_Z2kGcB1.webp&quot; srcset=&quot;/_astro/pexels-andrea-piacquadio-painter.DIvHNElN_Z22R9NA.webp 640w, /_astro/pexels-andrea-piacquadio-painter.DIvHNElN_ZEtGpt.webp 750w, /_astro/pexels-andrea-piacquadio-painter.DIvHNElN_1BcUX3.webp 828w, /_astro/pexels-andrea-piacquadio-painter.DIvHNElN_ZRUx6q.webp 1080w, /_astro/pexels-andrea-piacquadio-painter.DIvHNElN_2bUsKf.webp 1280w, /_astro/pexels-andrea-piacquadio-painter.DIvHNElN_Z2kGcB1.webp 1600w&quot; alt=&quot;Woman painting a cat figure on a piece of paper.&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1095&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Andrea Piacquadio / pexels.com&lt;/p&gt;
&lt;p&gt;How can you embed inline SVG images? What are best practices to customize them with CSS properties and variables? Read on
to find out more.&lt;/p&gt;
&lt;h2 id=&quot;how-to-embed-an-inline-svg&quot;&gt;How to embed an inline SVG&lt;/h2&gt;
&lt;p&gt;SVG images can be embedded directly in the HTML document using the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;svg&amp;gt;&lt;/code&gt;  tag. Simply
open the image file in the code editor of your choice, copy the code, and paste it into your HTML template. Here’s an example:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;svg&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; height&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;48&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; width&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;48&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; viewBox&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;0 -960 960 960&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; xmlns&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;http://www.w3.org/2000/svg&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;path&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; d&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;m393-165 279-335H492l36-286-253 366h154l-36 255Zm-73 85 40-280H160l360-520h80l-40 320h240L400-80h-80Zm153-395Z&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;path&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;svg&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nowadays, websites are often built with component-based JavaScript frameworks like &lt;a href=&quot;https://angular.io/&quot;&gt;Angular&lt;/a&gt; or
&lt;a href=&quot;https://react.dev/&quot;&gt;React&lt;/a&gt;. These allow you to wrap an inline SVG in its own component that you can easily reuse in different
sections of your website. One example for this pattern is the &lt;a href=&quot;https://mui.com/material-ui/material-icons/&quot;&gt;Material UI icon library&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The UI library &lt;a href=&quot;https://material.angular.io/components/icon/overview#svg-icons&quot;&gt;Angular Material&lt;/a&gt; even goes a step further:
You can add SVG files as assets to your website. The application later fetches the images from the server, allowing the SVG code
to be embedded in the HTML document via the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;mat-icon&amp;gt;&lt;/code&gt;  component.&lt;/p&gt;
&lt;h2 id=&quot;demo-flexible-styling-of-svg-icon-buttons&quot;&gt;Demo: Flexible styling of SVG Icon Buttons&lt;/h2&gt;
&lt;p&gt;I’ve created a &lt;a href=&quot;https://alexlehner86.github.io/fancy-css-playground/#/inlinesvg&quot;&gt;demo&lt;/a&gt; with use cases for inline SVGs. You can
customize the color of the icons through a color picker element:&lt;/p&gt;
&lt;iframe src=&quot;https://alexlehner86.github.io/fancy-css-playground/#/inlinesvg&quot; title=&quot;Demo: Flexible inline SVG styling&quot; loading=&quot;lazy&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;I accomplished this by linking the SVG image’s &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;fill&lt;/code&gt;  to the CSS property &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;color&lt;/code&gt; .&lt;/p&gt;
&lt;h2 id=&quot;customizing-the-svg-with-css&quot;&gt;Customizing the SVG with CSS&lt;/h2&gt;
&lt;p&gt;First, you set the SVG image’s &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;fill&lt;/code&gt;  property to the value &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;currentColor&lt;/code&gt; . This
special keyword represents the value of an element’s &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;color&lt;/code&gt;  CSS property. This way, the SVG image’s
vectors will be filled with the element’s font color. You can set the property in the SVG code:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;svg&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; fill&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;currentColor&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; height&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;48&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; width&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;48&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; viewBox&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;0 -960 960 960&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; xmlns&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;http://www.w3.org/2000/svg&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;path&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; d&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;...&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;path&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;svg&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or, you can set the property in your CSS code:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;.icon&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt; svg&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    fill&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;currentColor&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, you can control the appearance of the SVG image through the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;color&lt;/code&gt;  CSS property. This makes it
easier to manage color themes and different states of controls.&lt;/p&gt;
&lt;p&gt;Imagine you have a button with an icon and text, like in my demo above: You can color all elements inside the button with a
single CSS rule. You can easily style different states like &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;:hover&lt;/code&gt; , &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;:focus&lt;/code&gt; ,
or &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;:disabled&lt;/code&gt; . And you can even animate the color change:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;.primary-btn&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    color&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;#f118a6&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transition&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;color&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 0.5s&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; ease&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;.primary-btn:hover&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;.primary-btn:focus&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    color&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;#920c64&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    outline&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;2px&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; solid&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; currentColor&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;use-css-variables-for-multi-colored-images&quot;&gt;Use CSS Variables for Multi-Colored Images&lt;/h2&gt;
&lt;p&gt;You can even use &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties&quot;&gt;CSS variables&lt;/a&gt; inside SVG code.
This can be useful when you’re dealing with an SVG image that uses multiple colors. In this case, you can still link the main
color to the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;color&lt;/code&gt;  CSS property. Then, define CSS variables for the other colors:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;svg&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; fill&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;currentColor&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; viewBox&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;0 0 20 20&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; xmlns&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;http://www.w3.org/2000/svg&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;path&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; d&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;...&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;path&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; d&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;...&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;path&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; fill&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;var(--secondary-fill)&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; d&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;...&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;svg&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the example above, the first and second &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;path&lt;/code&gt;  elements are colored by the defined font color. The
fill of the third path can be controlled through the CSS variable &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;—secondary-fill&lt;/code&gt; :&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;.icon&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    color&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;darkred&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    --secondary-fill&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;white&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Check out the article &lt;a href=&quot;https://frontstuff.io/multi-colored-svg-symbol-icons-with-css-variables&quot;&gt;“Multi-Colored SVG Symbol Icons with CSS Variables”&lt;/a&gt;
for an in-depth look at the concept.&lt;/p&gt;
&lt;h2 id=&quot;make-your-images-accessible&quot;&gt;Make Your Images Accessible&lt;/h2&gt;
&lt;p&gt;Last, but not least: Don’t forget about accessibility! If the SVG image is purely decorative, then
use &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;aria-hidden=“true”&lt;/code&gt;  to hide the element from assistive technologies.&lt;/p&gt;
&lt;p&gt;If the image conveys important information, then assign &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;role=“img”&lt;/code&gt;  and provide alternative text
through the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;aria-label&lt;/code&gt;  attribute. Read &lt;a href=&quot;https://www.unimelb.edu.au/accessibility/techniques/accessible-svgs&quot;&gt;“Accessible SVGs”&lt;/a&gt;
for more information and use cases.&lt;/p&gt;</content:encoded><category>accessibility</category><category>css</category><category>design</category><category>html</category><category>images</category><category>svg</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_painter.jpg" length="0" type="image/jpeg"/></item><item><title>Use the inert attribute to prevent unintended user interaction</title><link>https://www.oidaisdes.org/blog/inert-attribute-prevents-interaction</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/inert-attribute-prevents-interaction</guid><description>An easy and elegant way to improve accessibility and the user experience.</description><pubDate>Thu, 04 May 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Web design is all about making efficient use of the available space. You don’t want to clutter the screen
with too much content. This is the reason for common patterns like slide-in submenus, expansion panels,
popups or dialogs.&lt;/p&gt;
&lt;p&gt;Often, these elements are implemented as custom widgets with an insufficient hidden state. They use CSS code
like &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;opacity: 0&lt;/code&gt;  or &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;position: absolute; left: -10000px&lt;/code&gt;  to
hide the content only visually. But users can still access the content with the keyboard or assistive technologies.
What can we do about it?&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-roxanne-minnish-sloth.9-mxRGvj_23V2hw.webp&quot; srcset=&quot;/_astro/pexels-roxanne-minnish-sloth.9-mxRGvj_Z1yMF8N.webp 640w, /_astro/pexels-roxanne-minnish-sloth.9-mxRGvj_1JEsvG.webp 750w, /_astro/pexels-roxanne-minnish-sloth.9-mxRGvj_ts9jV.webp 828w, /_astro/pexels-roxanne-minnish-sloth.9-mxRGvj_Z1wqqXI.webp 1080w, /_astro/pexels-roxanne-minnish-sloth.9-mxRGvj_Z2ifqY3.webp 1280w, /_astro/pexels-roxanne-minnish-sloth.9-mxRGvj_23V2hw.webp 1600w&quot; alt=&quot;Sloth hanging on tree branch.&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1067&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Roxanne Minnish / pexels.com&lt;/p&gt;
&lt;p&gt;You can use the HTML attribute &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;inert&lt;/code&gt;  to prevent any interaction with hidden content. A kind of
digital sloth, so to say. Let’s take a closer look at the attribute that is now supported by all major browsers.&lt;/p&gt;
&lt;h2 id=&quot;how-the-inert-attribute-works&quot;&gt;How the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;inert&lt;/code&gt;  attribute works&lt;/h2&gt;
&lt;p&gt;The inert property is a global HTML attribute that tells the browser to prevent any user interaction with a specific
section of content. The &lt;a href=&quot;https://html.spec.whatwg.org/#the-inert-attribute&quot;&gt;HTML specification&lt;/a&gt; states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;strong&gt;inert&lt;/strong&gt; attribute is a boolean attribute that indicates, by its presence, that the element and
all its flat tree descendants […] are to be made inert by the user agent.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This means that all user input events for the element and its descendants are ignored, including focus events and events
from assistive technologies.&lt;/p&gt;
&lt;p&gt;For example: Let’s say you place a registration form off-screen and let it slide into view
when the user presses a certain button. Adding &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;inert&lt;/code&gt;  to the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;form&amp;gt;&lt;/code&gt; 
element ensures that a keyboard user cannot accidentally interact with the form elements while they’re off-screen. The
content will also be hidden from screen reader users.&lt;/p&gt;
&lt;p&gt;The native &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt;  element also makes use of this. When you open a modal dialog
with &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;.showModal()&lt;/code&gt; , the browser will automatically render all other content inert.
Find out more in my blog post &lt;a href=&quot;/blog/native-dialog-element/&quot;&gt;“Why you should use the Native Dialog Element”&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;use-case-animated-navigation-menu&quot;&gt;Use Case: Animated Navigation Menu&lt;/h2&gt;
&lt;p&gt;I’ve created a &lt;a href=&quot;https://alexlehner86.github.io/fancy-css-playground/#/inert&quot;&gt;demo&lt;/a&gt; for an animated navigation menu that
uses the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;inert&lt;/code&gt;  attribute for its hidden submenus. It works well for keyboard and screen reader users:&lt;/p&gt;
&lt;iframe src=&quot;https://alexlehner86.github.io/fancy-css-playground/#/inert&quot; title=&quot;Use Case for inert attribute&quot; loading=&quot;lazy&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;The navigation menu is structured as an unordered list inside a nav element. The HTML code for a menu option and its
hidden submenu looks as follows:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;button&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; aria-expanded&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; aria-controls&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;sub_menu_research&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    Research&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;sub_menu_research&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;subMenu&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; inert&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; href&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;/black-holes&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Black Holes&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; href&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;/climate-change&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Climate Change&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; href&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;/modern-way-of-work&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Modern Way of Work&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In my CSS code, I reference the inert attribute to also visually hide the submenu:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;.subMenu&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    overflow&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;hidden&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;.subMenu&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;inert&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt; ul&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transform&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;translateY&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;-100%&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When the menu option is activated, the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;inert&lt;/code&gt;  attribute is removed and the submenu slides into view:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;.subMenu:not&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;inert&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;]) &lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt; ul&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transform&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;translateY&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The creation of the slide animation is pretty easy and straightforward using the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;transition&lt;/code&gt; 
CSS property:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;.subMenu&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt; ul&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transition&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: transform &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.4s&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; ease-in-out&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can view the &lt;a href=&quot;https://github.com/alexlehner86/fancy-css-playground/tree/main/src/pages/InertAttribute&quot;&gt;complete source code here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;wouldnt-display-none-do-the-job&quot;&gt;Wouldn’t &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;display: none&lt;/code&gt;  do the job?&lt;/h2&gt;
&lt;p&gt;Some of you might be thinking: &lt;span class=&quot;c-italic&quot;&gt;“Why should I use the inert attribute? I can simply hide stuff with
display: none, duh!”&lt;/span&gt;  You’re right. When you apply the CSS property &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;display: none&lt;/code&gt; 
to an element, it won’t be rendered by the browser and is hidden from assistive technologies. The downside: You
won’t be able to animate the element any more.&lt;/p&gt;
&lt;p&gt;Using the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;inert&lt;/code&gt;  attribute gives you more flexibility. You can let your content fade in and out,
slide into view or create any sophisticated animation you can think of. Also, you’ll want to use the attribute for content
that is visible but should not be interacted with. For example, the partially visible previous and next slide in
a carousel widget.&lt;/p&gt;
&lt;h2 id=&quot;browser-support&quot;&gt;Browser Support&lt;/h2&gt;
&lt;p&gt;Firefox finally added support for &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;inert&lt;/code&gt;  in version 112. This means that
&lt;a href=&quot;https://caniuse.com/mdn-api_htmlelement_inert&quot;&gt;all major browsers&lt;/a&gt; support the attribute now.&lt;/p&gt;
&lt;p&gt;Yay! Let’s go and build cool stuff with it.&lt;/p&gt;</content:encoded><category>accessibility</category><category>animation</category><category>html</category><category>keyboard</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_sloth.jpg" length="0" type="image/jpeg"/></item><item><title>How the Description List Element improves Accessibility and the Developer Experience</title><link>https://www.oidaisdes.org/blog/description-list-html-element</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/description-list-html-element</guid><description>Markup any list of key-value pairs to make your code more readable and convey semantic information to screen readers.</description><pubDate>Sun, 02 Apr 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Lists are among the basic building blocks of the web. Every web developer knows the HTML
elements &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;ul&amp;gt;&lt;/code&gt;  and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;ol&amp;gt;&lt;/code&gt;  for
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul&quot;&gt;unordered&lt;/a&gt;
and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ol&quot;&gt;ordered lists&lt;/a&gt;.
Yet few are familiar with their close relative &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;dl&amp;gt;&lt;/code&gt; , the
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dl&quot;&gt;description list&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A typical use case for the element is to implement a glossary with terms and definitions. In fact, you can do
a lot more with it. I would argue that any list of key-value pairs should be marked up as a description list.
It improves the &lt;a href=&quot;https://medium.com/swlh/what-is-dx-developer-experience-401a0e44a9d9&quot;&gt;developer experience&lt;/a&gt;
by making the code more readable. And it makes your content more accessible.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-ketut-subiyanto-confused-couple.BugMF6Zv_1wXcuY.webp&quot; srcset=&quot;/_astro/pexels-ketut-subiyanto-confused-couple.BugMF6Zv_145ewT.webp 640w, /_astro/pexels-ketut-subiyanto-confused-couple.BugMF6Zv_ZU0eR2.webp 750w, /_astro/pexels-ketut-subiyanto-confused-couple.BugMF6Zv_1ChllD.webp 828w, /_astro/pexels-ketut-subiyanto-confused-couple.BugMF6Zv_1NmJIP.webp 1080w, /_astro/pexels-ketut-subiyanto-confused-couple.BugMF6Zv_Z1heA8U.webp 1280w, /_astro/pexels-ketut-subiyanto-confused-couple.BugMF6Zv_1wXcuY.webp 1600w&quot; alt=&quot;Two people discussing the HTML code on the laptop monitor in front of them.&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1014&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Ketut Subiyanto / pexels.com&lt;/p&gt;
&lt;p&gt;We’ll take a look at the history of the element, see how it works and how it affects accessibility.&lt;/p&gt;
&lt;h2 id=&quot;a-quick-history-of-the-description-list-element&quot;&gt;A Quick History of the Description List Element&lt;/h2&gt;
&lt;p&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;dl&amp;gt;&lt;/code&gt;  element has existed since &lt;a href=&quot;https://www.w3.org/MarkUp/HTMLPlus/htmlplus_34.html&quot;&gt;HTML+&lt;/a&gt;
in the year 1993. The document defined the element as a “definition list”:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A &lt;strong&gt;definition list&lt;/strong&gt; is a list of terms and corresponding definitions. Definition lists are
typically formatted with the term flush-left and the definition, formatted paragraph style, indented after the term.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This narrow definition is still present in many minds today. But it no longer applies. The element’s definition was changed
in &lt;a href=&quot;https://html.spec.whatwg.org/multipage/grouping-content.html#the-dl-element&quot;&gt;HTML5&lt;/a&gt;, making it more versatile:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;strong&gt;dl element&lt;/strong&gt; represents an association list consisting of zero or more name-value groups
(a &lt;strong&gt;description list&lt;/strong&gt;). […] Name-value groups may be terms and definitions, metadata topics and
values, questions and answers, or any other groups of name-value data.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This means that the element can be used to markup any list of key-value pairs. For example, a list of metadata about
a client: name, address, telephone number, etc.&lt;/p&gt;
&lt;h2 id=&quot;how-to-use-the-dl-element&quot;&gt;How to use the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;dl&amp;gt;&lt;/code&gt;  element&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dl&quot;&gt;description list&lt;/a&gt; contains a list of terms and
descriptions that are defined with the HTML elements &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;dt&amp;gt;&lt;/code&gt;  (description term)
and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;dd&amp;gt;&lt;/code&gt;  (description details). Here’s an example for a list of metadata:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dl&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dt&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Account Owner&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dt&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dd&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Martina Musterfrau&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dd&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dt&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Banking Institute&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dt&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dd&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Musterbank&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dd&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dt&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;IBAN&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dt&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dd&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;AT12 3456 7891 2345 6789&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dd&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dt&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Telephone&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dt&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dd&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;+43 1234 56 78&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dd&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dl&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The semantic HTML tags convey important information to assistive technologies. Screen readers can navigate the
individual list items and convey the relationship between term and description. But web developers also benefit from
the semantic markup. Imagine the example above as a sequence of &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;div&amp;gt;&lt;/code&gt;  elements:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;metadata&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;term&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Account Owner&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;description&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Martina Musterfrau&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;term&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Banking Institute&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;description&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Musterbank&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;term&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;IBAN&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;description&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;AT12 3456 7891 2345 6789&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;term&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Telephone&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;description&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;+43 1234 56 78&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I hope you agree with me that the semantic HTML is easier to understand and work with. You can also leverage the
semantic tag names for expressive and easy to understand CSS selectors. Check out my article
&lt;a href=&quot;/blog/3-ways-web-devs-benefit-accessibility/&quot;&gt;“3 Ways how Web Developers also benefit from Accessibility”&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;styling-the-description-list&quot;&gt;Styling the Description List&lt;/h2&gt;
&lt;p&gt;The standard styling of description lists is rather bland. But don’t worry! You can freely customize the element with
CSS. The HTML specification allows wrapping each key-value pair in a &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;div&amp;gt;&lt;/code&gt;  element.&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dl&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dt&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Account Owner&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dt&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dd&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Martina Musterfrau&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dd&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dt&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Banking Institute&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dt&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dd&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Musterbank&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dd&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dt&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;IBAN&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dt&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dd&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;AT12 3456 7891 2345 6789&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dd&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dl&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This content structure enables us to create a responsive, horizontal layout using
&lt;a href=&quot;https://css-tricks.com/snippets/css/a-guide-to-flexbox/&quot;&gt;CSS flexbox&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;dl&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    display&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;flex&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    flex-wrap&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;wrap&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    gap&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1rem&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;dl&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt; div&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    flex-grow&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;dt&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    color&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;#6e2755&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    font-size&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.9rem&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    font-weight&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;bold&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;dd&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    font-size&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1rem&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    margin-inline-start&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here’s the end result:&lt;/p&gt;
&lt;iframe title=&quot;Flexbox styled Description List&quot; src=&quot;https://codepen.io/alexlehner86/embed/eYLwwaa?default-tab=result&quot; loading=&quot;lazy&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/alexlehner86/pen/eYLwwaa&quot;&gt;
Flexbox styled Description List&lt;/a&gt; by Alexander Lehner (&lt;a href=&quot;https://codepen.io/alexlehner86&quot;&gt;@alexlehner86&lt;/a&gt;)
on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;&lt;/iframe&gt;
&lt;h2 id=&quot;screen-reader-support&quot;&gt;Screen Reader Support&lt;/h2&gt;
&lt;p&gt;The description list element makes your content more accessible, especially for screen reader users. There are minor
differences between browsers and screen readers, but overall the support is generally good.
Adrian Roselli has done extensive screen reader testing for his article
&lt;a href=&quot;https://adrianroselli.com/2025/01/updated-brief-note-on-description-list-support.html&quot;&gt;“Updated Brief Note on Description List Support”&lt;/a&gt;.
Go check it out!&lt;/p&gt;
&lt;p&gt;I’d like to add one important aspect to his analysis: Screen readers are software applications. And software can have
bugs or miss an important feature (like the correct handling of the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;dl&amp;gt;&lt;/code&gt;  element). But
this should not stop us from using this feature. Especially if we can expect the screen reader vendor to fix their
mistakes in the near future.&lt;/p&gt;
&lt;h2 class=&quot;post-update-title&quot;&gt; &lt;span aria-hidden=&quot;true&quot;&gt;&amp;raquo;&amp;nbsp;&lt;/span&gt;Update on 04/18/2025 &lt;/h2&gt; 
&lt;p&gt;Added link to the updated blog article by Adrian Roselli.&lt;/p&gt;</content:encoded><category>accessibility</category><category>css</category><category>dx</category><category>html</category><category>layout</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_confused_couple.jpg" length="0" type="image/jpeg"/></item><item><title>Checklist for Accessible UI Component Libraries</title><link>https://www.oidaisdes.org/blog/accessible-ui-component-libraries</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/accessible-ui-component-libraries</guid><description>Provide a consistent, accessible design and speed up the development process.</description><pubDate>Wed, 22 Mar 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Accessibility is a choice. Designers can use color combinations with sufficient contrast, or pick colors
for purely aesthetic reasons. Web developers can implement a button with the native &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;button&lt;/code&gt; 
tag, or they use the generic &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;div&lt;/code&gt;  tag instead.&lt;/p&gt;
&lt;p&gt;In an ideal development process, accessibility is considered right from the start. The requirements clearly
state the needs of people with disabilities. Designers create mockups and prototypes which meet these requirements.
Developers implement the features with semantic markup. Testers verify that the web content meets the accessibility
requirements.&lt;/p&gt;
&lt;p&gt;In reality, accessibility is often treated as an afterthought. This can be especially problematic when it comes to
&lt;a href=&quot;https://medium.com/sketch-app-sources/why-should-you-build-a-ui-component-library-854656b91a96&quot;&gt;UI component libraries&lt;/a&gt;.
I will talk about why it’s important to check the accessibility of the library before you
write your first line of code. And what you should keep in mind when working with UI components.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-alena-darmel-lego-bricks.UC7mr8Jx_1evWOM.webp&quot; srcset=&quot;/_astro/pexels-alena-darmel-lego-bricks.UC7mr8Jx_UWsjP.webp 640w, /_astro/pexels-alena-darmel-lego-bricks.UC7mr8Jx_ZrxtDQ.webp 750w, /_astro/pexels-alena-darmel-lego-bricks.UC7mr8Jx_1vkU9o.webp 828w, /_astro/pexels-alena-darmel-lego-bricks.UC7mr8Jx_1Q5M5w.webp 1080w, /_astro/pexels-alena-darmel-lego-bricks.UC7mr8Jx_1WSJGf.webp 1280w, /_astro/pexels-alena-darmel-lego-bricks.UC7mr8Jx_1evWOM.webp 1600w&quot; alt=&quot;A toy is assembled from dozens of Lego bricks.&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1067&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Alena Darmel / pexels.com&lt;/p&gt;
&lt;h2 id=&quot;the-advantages-of-ui-component-libraries&quot;&gt;The Advantages of UI Component Libraries&lt;/h2&gt;
&lt;p&gt;HTML elements are the basic building blocks of any website. But they don’t cover all types of content and possible
use cases. Complex UI patterns like &lt;a href=&quot;https://www.w3.org/WAI/ARIA/apg/patterns/accordion/&quot;&gt;accordions&lt;/a&gt;,
&lt;a href=&quot;https://www.w3.org/WAI/ARIA/apg/patterns/carousel/&quot;&gt;carousels&lt;/a&gt;, or &lt;a href=&quot;https://www.w3.org/WAI/ARIA/apg/patterns/tabs/&quot;&gt;tabs&lt;/a&gt;
require custom implementations anyway.&lt;/p&gt;
&lt;p&gt;To speed up development and ensure a consistent look and feel, a modern web application usually makes use of a
UI component library. They’re a collection of design elements that are ready to use in your application. Usually, you
can apply a color theme and customize the functionality of the components.&lt;/p&gt;
&lt;p&gt;Hundreds of different component libraries are available for major web frameworks like &lt;a href=&quot;https://angular.io/&quot;&gt;Angular&lt;/a&gt;,
&lt;a href=&quot;https://react.dev/&quot;&gt;React&lt;/a&gt;, or &lt;a href=&quot;https://vuejs.org/&quot;&gt;Vue.js&lt;/a&gt;. For example, if you like the Material design system, you
can use &lt;a href=&quot;https://material.angular.io/&quot;&gt;Angular Material&lt;/a&gt;, &lt;a href=&quot;https://mui.com/&quot;&gt;Material UI&lt;/a&gt;, or
&lt;a href=&quot;https://matsp.github.io/material-components-vue/&quot;&gt;Material Components Vue&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;checking-the-librarys-accessibility&quot;&gt;Checking the Library’s Accessibility&lt;/h2&gt;
&lt;p&gt;Here’s a checklist for picking an accessible UI component library:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Is accessibility mentioned on the library’s website or documentation? For example, the Angular Material homepage states
that they offer: &lt;span class=&quot;c-italic&quot;&gt;“Internationalized and accessible components for everyone.”&lt;/span&gt; &lt;/li&gt;
&lt;li&gt;Does the documentation explain if and how the components are made accessible? The Angular Material documentation has
&lt;a href=&quot;https://material.angular.io/components/tabs/overview#accessibility&quot;&gt;dedicated accessibility sections&lt;/a&gt; for every component.&lt;/li&gt;
&lt;li&gt;The documentation usually includes demo pages and examples for the different components. Inspect their markup and
&lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/name-role-value.html&quot;&gt;accessibility properties&lt;/a&gt; using your browser’s dev tools.
Test with assistive technologies like your keyboard and different desktop and mobile screen readers.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;no-guarantee-of-complete-accessibility&quot;&gt;No Guarantee of Complete Accessibility&lt;/h2&gt;
&lt;p&gt;Picking an accessible UI component library is an important first step towards making you web application accessible.
But it doesn’t guarantee it. Every time you use a component on a page, you should answer the following questions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Where and how is the component included? Think about the context and order of content.&lt;/li&gt;
&lt;li&gt;Is the type of use consistent with the actual purpose of the component? Or are you only trying to achieve a specific
visual appearance?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The visual presentation of content should not determine which component you use. It’s easy to apply a specific design
with CSS. But it’s nearly impossible or at least very tedious to override a component’s semantic markup and implemented
keyboard interaction.&lt;/p&gt;
&lt;p&gt;To give you an example: Angular Material’s &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;mat-chip-listbox&amp;gt;&lt;/code&gt;  component provides a
multi-select listbox, following the &lt;a href=&quot;https://www.w3.org/WAI/ARIA/apg/patterns/listbox/&quot;&gt;listbox pattern&lt;/a&gt;. The semantic markup
communicates to assistive technologies that the element offers several options of which one or more can be selected.
The whole listbox receives keyboard focus via the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;TAB&lt;/code&gt;  key. The arrow keys move focus to the next
or previous option.&lt;/p&gt;
&lt;p&gt;Now imagine your client saying: &lt;span class=&quot;c-italic&quot;&gt;“I love the design of the chips component. I want this list of links styled
in the same way!”&lt;/span&gt;  Do you think you should really use the component for this use case?&lt;/p&gt;
&lt;p&gt;It’s our responsibility as web developers to pick the right component for the job. And to resist the seemingly easy path
that would lead to disaster! 😉&lt;/p&gt;</content:encoded><category>accessibility</category><category>angular</category><category>design</category><category>frameworks</category><category>html</category><category>react</category><category>ux</category><category>vuejs</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_lego_bricks.jpg" length="0" type="image/jpeg"/></item><item><title>Responsive Component Design with CSS Container Queries</title><link>https://www.oidaisdes.org/blog/responsive-design-container-queries</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/responsive-design-container-queries</guid><description>Create responsive, reusable components that adapt to the available space of their container.</description><pubDate>Fri, 17 Feb 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Everything is in flux. Modern web design has to account for a seemingly endless array of different screen sizes.
With &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@media&lt;/code&gt;  queries, you can style elements based on features of the browser viewport, e.g,
the screen’s width.&lt;/p&gt;
&lt;p&gt;But what if you want to create reusable components that are responsive to the container they’re placed in? For example,
a news card that can span the whole width of the website or fit into a narrow column on the side. We can do that now!&lt;/p&gt;
&lt;p&gt;With &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;CSS Container Queries&lt;/code&gt;  we can design responsive, reusable components that adapt to the
available space. With the recent &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Releases/110&quot;&gt;release of Firefox 110&lt;/a&gt;,
the feature is now &lt;a href=&quot;https://caniuse.com/css-container-queries&quot;&gt;supported by all major browsers&lt;/a&gt;. This is a total game
changer! Let’s see how it works.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-pixabay-coffee-cans.W8tA7_oK_mscO5.webp&quot; srcset=&quot;/_astro/pexels-pixabay-coffee-cans.W8tA7_oK_214JJm.webp 640w, /_astro/pexels-pixabay-coffee-cans.W8tA7_oK_TqbL8.webp 750w, /_astro/pexels-pixabay-coffee-cans.W8tA7_oK_kK2xd.webp 828w, /_astro/pexels-pixabay-coffee-cans.W8tA7_oK_Z2cDTLl.webp 1080w, /_astro/pexels-pixabay-coffee-cans.W8tA7_oK_Z1Ip6Kq.webp 1280w, /_astro/pexels-pixabay-coffee-cans.W8tA7_oK_mscO5.webp 1600w&quot; alt=&quot;Different size coffee cans stacked on top of each other.&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1067&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Pixabay / pexels.com&lt;/p&gt;
&lt;h2 id=&quot;query-the-size-of-containers&quot;&gt;Query the Size of Containers&lt;/h2&gt;
&lt;p&gt;Container queries allow us to apply styles to elements based on the size of their container rather than the viewport.
The feature is defined in the CSS Module &lt;a href=&quot;https://www.w3.org/TR/css-contain-3/#container-queries&quot;&gt;CSS Containment Module Level 3&lt;/a&gt;.
The document states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;While media queries provide a method to query aspects of the user agent or device environment that a document is being
displayed in (such as viewport dimensions or user preferences), &lt;strong&gt;container queries&lt;/strong&gt; allow testing aspects of
elements within the document (such as box dimensions or computed styles).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We can query different size container features like &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;width&lt;/code&gt; , &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;height&lt;/code&gt; 
or &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;inline-size&lt;/code&gt; . The specification also includes &lt;a href=&quot;https://www.w3.org/TR/css-contain-3/#style-container&quot;&gt;container style queries&lt;/a&gt;,
but those aren’t supported by browsers yet.&lt;/p&gt;
&lt;p&gt;To style a component based on its parent size, we need to set containment on the parent element with
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;container-type&lt;/code&gt;  CSS property. It’s recommended to also name the container
using &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;container-name&lt;/code&gt; . Here’s an example:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;.news-card&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    container-type&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: inline-size;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    container-name&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: news-card;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also set the type and name simultaneously with the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;container&lt;/code&gt;  shorthand property:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;.news-card&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    container&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: news-card / inline-size;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can query the container with the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@container&lt;/code&gt;  CSS at-rule and apply some conditional
styling. For example, if the container’s width is below a certain threshold:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@container&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; news-card (max-width: 25rem) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;    .card-image&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        flex-basis&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;100%&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;demo-responsive-news-card&quot;&gt;Demo: Responsive News Card&lt;/h2&gt;
&lt;p&gt;I’ve created a simple &lt;a href=&quot;https://codepen.io/alexlehner86/pen/abaOdLw&quot;&gt;demo on CodePen&lt;/a&gt; that shows a news card component.
If enough space is available, the card lays out its content horizontally. If the container’s width falls below a certain
threshold, the text is moved below the image.&lt;/p&gt;
&lt;iframe title=&quot;Code example for CSS Container Queries&quot; src=&quot;https://codepen.io/alexlehner86/embed/abaOdLw?default-tab=result&quot; loading=&quot;lazy&quot; allowtransparency=&quot;true&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/alexlehner86/pen/abaOdLw&quot;&gt;
CSS Container Queries Demo&lt;/a&gt; by Alexander Lehner (&lt;a href=&quot;https://codepen.io/alexlehner86&quot;&gt;@alexlehner86&lt;/a&gt;)
on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;&lt;/iframe&gt;
&lt;h2 id=&quot;further-reading&quot;&gt;Further Reading&lt;/h2&gt;
&lt;p&gt;There’s a lot more to learn about container queries. Check out the following guides and examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ishadeed.com/article/container-queries-are-finally-here/&quot;&gt;“CSS container queries are finally here”, by Ahmad Shadeed&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://css-tricks.com/early-days-of-container-style-queries/&quot;&gt;“Early Days of Container Style Queries”, by Geoff Graham&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.oddbird.net/2022/08/18/cq-syntax/&quot;&gt;“Use the Right Container Query Syntax”, by Miriam Suzanne&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.matuzo.at/blog/2022/100daysof-day56/&quot;&gt;“Day 56: container queries”, by Manuel Matuzović&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/cq-stable/&quot;&gt;“Container queries land in stable browsers”, by Una Kravets&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I’m super excited about CSS container queries! Yet, I’ve barely scratched the surface of all the possible use cases.
My goal is to use the feature in more and more projects and contiuously improve my understanding of it.&lt;/p&gt;
&lt;p&gt;In my opinion, one thing is certain: Container queries will change the way we write CSS for good. What ideas and
use cases have you already implemented with the feature?&lt;/p&gt;</content:encoded><category>css</category><category>components</category><category>design</category><category>layout</category><category>responsive</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_coffee_cans.jpg" length="0" type="image/jpeg"/></item><item><title>Design Perfectly Aligned Layouts with CSS Subgrid</title><link>https://www.oidaisdes.org/blog/aligned-layouts-with-css-subgrid</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/aligned-layouts-with-css-subgrid</guid><description>Nested grid containers can align their rows and columns using the subgrid feature.</description><pubDate>Sun, 29 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout&quot;&gt;CSS Grid Layout&lt;/a&gt; is a two-dimensional grid-based
layout system for websites. It makes it easy to arrange content in rows and columns and create responsive layouts.&lt;/p&gt;
&lt;p&gt;If you’re familiar with grid layouts, you’ve probably encountered the following issue: A grid container can
be placed inside another grid to create a &lt;a href=&quot;https://gridbyexample.com/examples/example21/&quot;&gt;nested grid layout&lt;/a&gt;.
Unfortunately, the content of the child grid doesn’t automatically align with the parent grid. But don’t worry!
We can solve this issue with the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;subgrid&lt;/code&gt;  feature!&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-rodnae-productions-chess-board.DBARuRnP_Z2DAz8.webp&quot; srcset=&quot;/_astro/pexels-rodnae-productions-chess-board.DBARuRnP_ECszp.webp 640w, /_astro/pexels-rodnae-productions-chess-board.DBARuRnP_1WPcBH.webp 750w, /_astro/pexels-rodnae-productions-chess-board.DBARuRnP_Z1xQojE.webp 828w, /_astro/pexels-rodnae-productions-chess-board.DBARuRnP_ZEf0ue.webp 1080w, /_astro/pexels-rodnae-productions-chess-board.DBARuRnP_i2IxQ.webp 1280w, /_astro/pexels-rodnae-productions-chess-board.DBARuRnP_Z2DAz8.webp 1600w&quot; alt=&quot;A chessboard with a grid of rows and columns.&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1067&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © RODNAE Productions / pexels.com&lt;/p&gt;
&lt;p&gt;The subgrid feature makes grid layout even more powerful and enables us to create perfectly aligned layouts.
I’ve prepared a demo of a typical use case. Let’s see how it all works.&lt;/p&gt;
&lt;h2 id=&quot;the-basics-of-grid-layout&quot;&gt;The Basics of Grid Layout&lt;/h2&gt;
&lt;p&gt;The grid layout system is defined in the &lt;a href=&quot;https://www.w3.org/TR/css-grid-2/&quot;&gt;CSS Grid Layout Module&lt;/a&gt; specification:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A &lt;strong&gt;two-dimensional grid-based layout system&lt;/strong&gt;, optimized for user interface design. In the grid layout model,
the children of a grid container can be positioned into arbitrary slots in a predefined flexible or fixed-size layout grid.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You can turn an HTML element into a grid container with the CSS property &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;display: grid&lt;/code&gt; . Next, you can
define the rows and columns with the properties &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;grid-template-rows&lt;/code&gt; 
and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;grid-template-columns&lt;/code&gt; .&lt;/p&gt;
&lt;p&gt;There are many ways to define a grid and populate it with content. Listing all possible settings and scenarios would go beyond
the scope of this article. If you want to learn more, I can recommend the tutorials
&lt;a href=&quot;https://css-tricks.com/snippets/css/complete-guide-grid/&quot;&gt;“A Complete Guide to CSS Grid”&lt;/a&gt; and
&lt;a href=&quot;https://learncssgrid.com/&quot;&gt;“Learn CSS Grid”&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what-is-subgrid-and-whats-it-good-for&quot;&gt;What is Subgrid and What’s it Good for?&lt;/h2&gt;
&lt;p&gt;The subgrid feature was added in &lt;a href=&quot;https://www.w3.org/TR/css-grid-2/#subgrids&quot;&gt;CSS Grid Layout Module Level 2&lt;/a&gt;.
The specification states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A nested grid can defer the definition of its rows and/or columns to its parent grid container, making it a subgrid.
In this case, the grid items of the subgrid participate in sizing the parent grid, allowing the contents of both grids to align.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To define a subgrid, you simply set the value &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;subgrid&lt;/code&gt;  for the
property &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;grid-template-rows&lt;/code&gt;  or &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;grid-template-columns&lt;/code&gt; . That’s it! The
nested grid will now use the columns and/or rows defined by the parent grid and align its content accordingly.&lt;/p&gt;
&lt;h2 id=&quot;demo-punk-api-beer-list&quot;&gt;Demo: Punk API Beer List&lt;/h2&gt;
&lt;p&gt;I’ve created a &lt;a href=&quot;https://github.com/alexlehner86/punk-api-beer-list&quot;&gt;React demo&lt;/a&gt; that displays a list of beers in a grid with
three equally sized columns. Each grid cell contains information about a specific beer. Check out
the &lt;a href=&quot;https://alexlehner86.github.io/punk-api-beer-list/&quot;&gt;live version here&lt;/a&gt; (best viewed on a desktop screen).&lt;/p&gt;
&lt;iframe src=&quot;https://alexlehner86.github.io/punk-api-beer-list/&quot; title=&quot;Demo Page: Beer List with Subgrid Feature&quot; loading=&quot;lazy&quot;&gt;&lt;/iframe&gt;
&lt;h3 id=&quot;the-parent-grid-container&quot;&gt;The Parent Grid Container&lt;/h3&gt;
&lt;p&gt;The demo uses an unordered list as the parent grid container. Here’s the &lt;a href=&quot;https://reactjs.org/docs/introducing-jsx.html&quot;&gt;JSX code&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; className&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;styles&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;beerGrid&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;    {&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;items&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;item&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; key&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;item&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;            &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;BeerItemDetails&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; item&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;item&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;    ))&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In my CSS code, I use the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;repeat&lt;/code&gt;  and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;minmax&lt;/code&gt;  functions to create a grid
with three columns and a variable number of rows. Each column is equally sized with a minimum width of &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;15rem&lt;/code&gt; .&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;ul.beerGrid&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    display&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;grid&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    gap&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;2.5rem&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    grid-template-columns&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;repeat&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;minmax&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;15rem&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1fr&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    grid-template-rows&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;auto&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    list-style&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;none&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;turning-the-beer-content-cards-into-subgrids&quot;&gt;Turning the Beer Content Cards into Subgrids&lt;/h3&gt;
&lt;p&gt;Each list item is rendered using the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;BeerItemDetails&lt;/code&gt;  React component. This component
consists of a header section (&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;hgroup&lt;/code&gt;  element) and a details section
(&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;div&lt;/code&gt;  element):&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;hgroup&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; className&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;styles&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;heading&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;item&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;item&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;tagline&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;hgroup&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; className&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;styles&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;flexRow&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    &amp;lt;!-- details --&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In my CSS code, I define the list items as grid containers with two rows (&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;grid-row: span 2&lt;/code&gt; ).
The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;grid-template-rows: subgrid&lt;/code&gt;  declaration tells the browser to align the header and details
section of each beer card that is placed on the same row.&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;ul.beerGrid&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt; li&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    display&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;grid&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    grid-template-rows&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;subgrid&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    grid-row&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: span &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    gap&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;easier-development-with-css-grid-inspector&quot;&gt;Easier Development with CSS Grid Inspector&lt;/h3&gt;
&lt;p&gt;I made heavy use of the &lt;a href=&quot;https://firefox-source-docs.mozilla.org/devtools-user/page_inspector/how_to/examine_grid_layouts/&quot;&gt;CSS Grid Inspector&lt;/a&gt;
that is part of Firefox DevTools. This awesome tool highlights your grid’s rows and columns and makes it easier to understand
how the parent grid and its subgrids fit together.&lt;/p&gt;
&lt;p&gt;The Chrome DevTools offer a &lt;a href=&quot;https://developer.chrome.com/docs/devtools/css/grid/&quot;&gt;similar tool&lt;/a&gt;. But as a passionate Firefox user, I just
had to mention the Firefox tool first. 😉&lt;/p&gt;
&lt;h2 id=&quot;browser-support-and-progressive-enhancement&quot;&gt;Browser Support and Progressive Enhancement&lt;/h2&gt;
&lt;p&gt;At the time of publication of this post, only Safari and Firefox &lt;a href=&quot;https://caniuse.com/css-subgrid&quot;&gt;support the subgrid feature&lt;/a&gt;.
But don’t worry! You don’t have to wait for Chrome and Edge to catch up.&lt;/p&gt;
&lt;p&gt;Apply the principle of &lt;a href=&quot;https://en.wikipedia.org/wiki/Progressive_enhancement&quot;&gt;progressive enhancement&lt;/a&gt; to provide a basic layout and
also take advantage of the subgrid feature in supporting browsers. To achieve this, we use &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@supports&lt;/code&gt;  to check
browser support before we set the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;subgrid&lt;/code&gt;  value:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@supports&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;grid-template-rows&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;subgrid&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;    ul.beerGrid&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt; li&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        display&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;grid&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        grid-template-rows&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;subgrid&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;useful-resources&quot;&gt;Useful Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/css-grid-2/&quot;&gt;CSS Grid Layout Module Level 2 (specification)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://css-tricks.com/snippets/css/complete-guide-grid/&quot;&gt;“A Complete Guide to CSS Grid” (CSS Tricks)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gridbyexample.com/&quot;&gt;“Grid by Example” (Rachel Andrew)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://learncssgrid.com/&quot;&gt;“Learn CSS Grid” (Jonathan Suh)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ishadeed.com/article/learn-css-subgrid/&quot;&gt;“Learn CSS Subgrid” (Ahmad Shadeed)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>css</category><category>design</category><category>html</category><category>layout</category><category>react</category><category>ux</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_chess_board.jpg" length="0" type="image/jpeg"/></item><item><title>Create an Accessible News Carousel as an Angular Standalone Component</title><link>https://www.oidaisdes.org/blog/accessible-news-carousel</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/accessible-news-carousel</guid><description>Using Angular, ARIA attributes and some powerful CSS, we create an accessible, responsive web carousel.</description><pubDate>Sun, 15 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I love carousels! The colorful theme park rides with animals and chariots are often beautifully crafted.
Kids can spend hours on them, going round and round. Pure joy!&lt;/p&gt;
&lt;p&gt;Can I say the same about carousel UI components? Not so much. I actually dislike most forms of web carousels,
especially when they change slides by themselves. Also, most of them are inaccessible nightmares. So, I said
to myself: Let’s do better!&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-alexander-nadrilyanski-carousel.D_DxkHhP_6Xrmv.webp&quot; srcset=&quot;/_astro/pexels-alexander-nadrilyanski-carousel.D_DxkHhP_1pSCWl.webp 640w, /_astro/pexels-alexander-nadrilyanski-carousel.D_DxkHhP_Z2djl4k.webp 750w, /_astro/pexels-alexander-nadrilyanski-carousel.D_DxkHhP_Z1zbpFf.webp 828w, /_astro/pexels-alexander-nadrilyanski-carousel.D_DxkHhP_1XKNAx.webp 1080w, /_astro/pexels-alexander-nadrilyanski-carousel.D_DxkHhP_1s82oF.webp 1280w, /_astro/pexels-alexander-nadrilyanski-carousel.D_DxkHhP_6Xrmv.webp 1600w&quot; alt=&quot;A carousel at night with bright lights. Figures of a horse and tiger are visible.&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1064&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Alexander Nadrilyanski / pexels.com&lt;/p&gt;
&lt;p&gt;I’ve created a &lt;a href=&quot;https://github.com/alexlehner86/accessible-news-carousel&quot;&gt;news carousel&lt;/a&gt; as an
&lt;a href=&quot;https://angular.io/guide/standalone-components&quot;&gt;Angular standalone component&lt;/a&gt;. It’s accessible, responsive and
has smooth animations. Let’s take a look at how it’s built and how it works.&lt;/p&gt;
&lt;h2 id=&quot;demo-accessible-news-carousel&quot;&gt;Demo: Accessible News Carousel&lt;/h2&gt;
&lt;p&gt;My &lt;a href=&quot;https://alexlehner86.github.io/accessible-news-carousel/&quot;&gt;demo application&lt;/a&gt; displays a list of news items,
each with a heading, text snippet and a background image. Users can move from slide to slide using swipe gestures
or the navigation buttons.&lt;/p&gt;
&lt;iframe src=&quot;https://alexlehner86.github.io/accessible-news-carousel/&quot; title=&quot;Demo Page: Accessible News Carousel&quot; loading=&quot;lazy&quot;&gt;&lt;/iframe&gt;
&lt;h2 id=&quot;design-and-accessibility-requirements&quot;&gt;Design and Accessibility Requirements&lt;/h2&gt;
&lt;p&gt;There is no native HTML element for web carousels. That’s why there are so many different custom implementations.
At least, the W3C has defined basic requirements in their “ARIA Authoring Practices Guide”. Their definition of
the &lt;a href=&quot;https://www.w3.org/WAI/ARIA/apg/patterns/carousel/&quot;&gt;carousel pattern&lt;/a&gt; states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A &lt;strong&gt;carousel&lt;/strong&gt; presents a set of items, referred to as slides, by sequentially displaying a subset
of one or more slides. Typically, one slide is displayed at a time, and users can activate a next or previous slide
control that hides the current slide and “rotates” the next or previous slide into view.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This abstract definition applies to basic image rotators as well as slide shows with complex content. In general,
carousels should fulfill the following requirements:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It should convey its structure to assistive technologies.&lt;/li&gt;
&lt;li&gt;It should indicate the currently active slide, both visually and to assistive technologies.&lt;/li&gt;
&lt;li&gt;Users should &lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/pointer-gestures.html&quot;&gt;not be forced to use swipe gestures&lt;/a&gt;
to operate the carousel. It should offer simple controls that the user can click on or operate with the keyboard.&lt;/li&gt;
&lt;li&gt;Dynamic content changes of the carousel (e.g. moving to the next slide) should be communicated to screen reader users
via &lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/status-messages.html&quot;&gt;status messages&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If the carousel can automatically rotate, it also has a button for stopping and restarting rotation.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I hate moving content that starts automatically. That’s why my news carousel doesn’t rotate on its own and, therefore,
has no pause button.&lt;/p&gt;
&lt;h2 id=&quot;content-structure-and-semantic-markup&quot;&gt;Content Structure and Semantic Markup&lt;/h2&gt;
&lt;h3 id=&quot;the-carousel-container&quot;&gt;The Carousel Container&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.w3.org/TR/wai-aria-1.2/&quot;&gt;ARIA specification&lt;/a&gt; doesn’t include a &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;carousel&lt;/code&gt;  role.
Therefore, you need to set the generic &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;role=“region”&lt;/code&gt;  and provide a custom description
with &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;aria-roledescription=“carousel”&lt;/code&gt; . An accessible label is provided
by the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;aria-label&lt;/code&gt;  attribute.&lt;/p&gt;
&lt;p&gt;In my &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;NewsCarouselComponent&lt;/code&gt; , I use the &lt;a href=&quot;https://angular.io/api/core/HostBinding&quot;&gt;HostBinding&lt;/a&gt; decorator to apply these
properties to the carousel component’s container:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;/**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;* The aria label for the carousel container.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;* It should convey to screenreader users what the carousel is about.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;HostBinding&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;#39;attr.aria-label&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) @&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;Input&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; carouselLabel&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;HostBinding&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;#39;attr.role&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;#39;region&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;HostBinding&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;#39;attr.aria-roledescription&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; carouselDescription&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;() { &lt;/span&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;carouselDescription&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The carousel includes two icon buttons to navigate to the previous or next slide. Accessible labels are provided by
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;aria-label&lt;/code&gt;  attribute set on the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;button&lt;/code&gt;  tags.&lt;/p&gt;
&lt;h3 id=&quot;the-slide-container&quot;&gt;The Slide Container&lt;/h3&gt;
&lt;p&gt;Each slide container has &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;role=“group”&lt;/code&gt;  and the property &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;aria-roledescription&lt;/code&gt; 
set to “slide”. The slide container’s &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;aria-label&lt;/code&gt;  attribute conveys the slide’s number and the total
set size (e.g., “2 of 5”).&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    *ngFor&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;let item of newsItems; let i = index&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    class&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;news-item&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;group&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    [attr.aria-roledescription]&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;config.slideDescription&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    [attr.aria-label]&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;(i + 1) + &amp;#39; &amp;#39; + config.slideLabel + &amp;#39; &amp;#39; + newsItems.length&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;    &amp;lt;!-- slide content --&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The disadvantage of custom role descriptions is that they’re not automatically translated by screen readers. If you’re
building a multi-lingual website, you’ll need to keep that in mind. My &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;NewsCarouselComponent&lt;/code&gt; 
has a &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;config&lt;/code&gt;  input property with default values in English that can be overriden.&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;Input&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; config: &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;NewsCarouselConfig&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    carouselDescription:&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;#39;carousel&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    slideDescription:&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;#39;slide&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    slideLabel:&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;#39;of&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    nextButtonLabel:&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;#39;Next slide&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    previousButtonLabel:&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;#39;Previous slide&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;avoid-list-markup&quot;&gt;Avoid List Markup&lt;/h3&gt;
&lt;p&gt;A common mistake is to use list markup for the slides. Screen readers announce the number of items in a list, but ignore
list items that are hidden. In my component, only the visible slide is also presented to assistive technologies. The other
slides are visually and programmatically hidden using the CSS property &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;visibility: hidden&lt;/code&gt; .&lt;/p&gt;
&lt;p&gt;If I’d implement all slides as &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;li&amp;gt;&lt;/code&gt;  elements inside an unordered
list (&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;ul&amp;gt;&lt;/code&gt; ), then the screen reader would announce the presence of a list with only one item.
This would not match the true number of slides and be confusing for the user.&lt;/p&gt;
&lt;h3 id=&quot;aria-live-region&quot;&gt;ARIA Live Region&lt;/h3&gt;
&lt;p&gt;The carousel should communicate dynamic content changes to screen reader users via status messages.
At first, I tried to turn the container element for all slides into an
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions&quot;&gt;ARIA live region&lt;/a&gt;. The results were not
satisfying. Due to the implementation of the slide transition using the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;visibility&lt;/code&gt;  CSS property,
the screen reader would announce the new slide several times or announce the wrong slide.&lt;/p&gt;
&lt;p&gt;I tried different approaches using properties like &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;aria-busy&lt;/code&gt;  and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;aria-relevant&lt;/code&gt; .
They only ever worked for some browser and screen reader combinations. So, in the end I chose the simple approach of putting
a &lt;a href=&quot;https://webaim.org/techniques/css/invisiblecontent/&quot;&gt;visually hidden&lt;/a&gt; ARIA live region at the end of the carousel container.
It’s a bit redundant, but it works!&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    class&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;active-slide-live-region&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    aria-live&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;polite&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;    {&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;{config.slideDescription + &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; + (activeSlideIndex + 1) + &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; + config.slideLabel + &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; + newsItems.length + &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;#39;:&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;    {&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;{newsItems&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;[activeSlideIndex].heading}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;keyboard-operability-and-swipe-gestures&quot;&gt;Keyboard Operability and Swipe Gestures&lt;/h2&gt;
&lt;p&gt;I love swiping! When I come across a carousel on a website, I instinctively try to swipe its content. Swiping itself is
not evil. But a web carousel that is only operable through swipe gestures is!&lt;/p&gt;
&lt;p&gt;Swipe gestures are inaccessible to many people with motor disabilities. They prefer
&lt;a href=&quot;https://www.accessguide.io/guide/single-pointer-gestures&quot;&gt;single-pointer alternatives&lt;/a&gt; like a clickable button. Also,
keyboard users require controls they can tab to and activate with the space or enter key.&lt;/p&gt;
&lt;p&gt;This is why I try to make everyone happy! My Angular component implements swipe gestures using
the &lt;a href=&quot;https://hammerjs.github.io/&quot;&gt;Hammer.js library&lt;/a&gt; and also includes buttons to navigate to the previous or next slide.&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;news-carousel-controls&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        type&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;button&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        [attr.aria-label]&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;config.previousButtonLabel&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        (click)&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;this.showPreviousSlide()&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;        &amp;lt;!-- arrow icon --&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        type&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;button&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        [attr.aria-label]&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;config.nextButtonLabel&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        (click)&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;this.showNextSlide()&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;        &amp;lt;!-- arrow icon --&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;slide-transitions-with-css-animations&quot;&gt;Slide Transitions with CSS Animations&lt;/h2&gt;
&lt;p&gt;I wanted to create beautiful transitions between slides with smooth slide in and out animations. Angular provides
its own &lt;a href=&quot;https://angular.io/guide/animations&quot;&gt;animations module&lt;/a&gt;. But I wanted to find a solution that would reduce
the build size and be efficient at the same time. Which is why I decided to use
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Using_CSS_animations&quot;&gt;CSS animations&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Creating animations with CSS is super simple and elegant. First, you define keyframes for your named animations.
Each keyframe describes how the animated element should render at a given time during the animation sequence.&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;// Keyframes for slide animation from left to right&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@keyframes&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; slide-in-from-left&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    0% {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        transform&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;translateX&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;-100%&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    100% {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        transform&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;translateX&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0%&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@keyframes&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; slide-out-to-right&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    0% {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        transform&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;translateX&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0%&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        visibility&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;visible&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    100% {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        transform&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;translateX&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;100%&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        visibility&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;hidden&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, you apply these animations to specific slides using the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;animation&lt;/code&gt;  CSS property. This shorthand
allows you to define a wide range of animation related properties (e.g., name, duration, direction) in a single CSS rule.&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;app-news-carousel&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt; .news-carousel-items.animate-from-left&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt; .news-item&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    &amp;amp;.active {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        animation&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: slide-in-from-left &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.5s&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; forwards&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    &amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;.moved-out&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        animation&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: slide-out-to-right &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.5s&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; forwards&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        border-left&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.125rem&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; solid&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; white&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the example above, two HTML elements are animated: The element with the class &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;active&lt;/code&gt;  slides
in from the left while the other element with the class &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;moved-out&lt;/code&gt;  slides out to the right.&lt;/p&gt;
&lt;h2 id=&quot;responsive-design-and-custom-styling&quot;&gt;Responsive Design and Custom Styling&lt;/h2&gt;
&lt;h3 id=&quot;flexible-layout-with-max-width-and-container-queries&quot;&gt;Flexible Layout with &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;max-width&lt;/code&gt;  and Container Queries&lt;/h3&gt;
&lt;p&gt;An application that uses the carousel component can set the CSS variable &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;—news-carousel-max-width&lt;/code&gt; 
to define a basic width for the carousel container. If no variable is set, then the fallback value of
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;var() function&lt;/code&gt;  is used.&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;app-news-carousel&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    height&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;--news-carousel-height&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;25rem&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    width&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;--news-carousel-max-width&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;50rem&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    max-width&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;100%&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By setting &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;max-width: 100%&lt;/code&gt;  we ensure that the containers width is limited by the space available
to its parent element. This way, the carousel never uses up more space than the viewport width of the device.&lt;/p&gt;
&lt;p&gt;Furthermore, I use &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries&quot;&gt;CSS Container Queries&lt;/a&gt;
to adapt the carousel’s styling if the container’s width is below a certain threshold. This new, powerful feature will soon
be &lt;a href=&quot;https://caniuse.com/css-container-queries&quot;&gt;supported by all major browsers&lt;/a&gt;. I’ll take a closer look at it in a
separate blog post.&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@container&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; news-carousel (max-width: 28rem) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;    app-news-carousel&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt; .news-item&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt; .slide-text&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        bottom&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.5rem&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        border-radius&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.5rem&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        width&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;calc&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;100%&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 1rem&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        p {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            display&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;none&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;custom-styling-with-css-variables&quot;&gt;Custom Styling with CSS Variables&lt;/h3&gt;
&lt;p&gt;CSS variables are great for component libraries. You can define a default styling and allow the user to override specific
styles by defining the responding variable. An application using my &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;NewsCarouselComponent&lt;/code&gt; 
can customize the following style properties via CSS variables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;—news-carousel-height&lt;/code&gt; : Set the height of the carousel.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;—news-carousel-max-width&lt;/code&gt; : Set the max width of the carousel. The carousel’s actual width is responsive to its container.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;—news-carousel-button-background&lt;/code&gt; : The background (color) of the previous and next buttons.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;—news-carousel-button-color&lt;/code&gt; : The color of the arrow icon in the previous and next buttons.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;—carousel-text-background&lt;/code&gt; : The background (color) of the slides’ text container.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;—carousel-text-color&lt;/code&gt; : The text color of the slides’ text container.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;—news-carousel-slide-focus-color&lt;/code&gt; : The color of the slides’ focus indicator.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-else-to-say&quot;&gt;What Else to Say&lt;/h2&gt;
&lt;p&gt;I want to make one thing clear: My carousel component is only one of several ways to implement an accessible, responsive
carousel. Yes, I’m pretty confident that my implementation is awesome. But of course, there’s other valid approaches as well.&lt;/p&gt;
&lt;p&gt;Web standards, browsers and assistive technologies are always evolving and changing. So, in a few years, or maybe even in a
few months, there might be a better solution. I can’t wait to see it! 😊&lt;/p&gt;
&lt;h2 id=&quot;useful-resources&quot;&gt;Useful Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/WAI/ARIA/apg/&quot;&gt;ARIA Authoring Practices Guide (APG)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/wai-aria-1.2/&quot;&gt;ARIA 1.2 specification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://angular.io/guide/standalone-components&quot;&gt;Angular standalone components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Using_CSS_animations&quot;&gt;CSS Animations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries&quot;&gt;CSS Container Queries&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>accessibility</category><category>angular</category><category>animation</category><category>aria</category><category>carousel</category><category>css</category><category>html</category><category>keyboard</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_carousel.jpg" length="0" type="image/jpeg"/></item><item><title>Looking Back at 2022 — My First Year of Blogging</title><link>https://www.oidaisdes.org/blog/looking-back-at-2022</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/looking-back-at-2022</guid><description>One year ago I started my blog about web development and accessibility. A retrospective and a look ahead.</description><pubDate>Thu, 29 Dec 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;One year ago, I took the course “Full Stack for Front-End Engineers” at &lt;a href=&quot;https://frontendmasters.com&quot;&gt;Frontend Masters&lt;/a&gt;.
I set up my own web server, bought a domain and started a web development blog using the &lt;a href=&quot;https://www.gatsbyjs.com/&quot;&gt;Gatsby framework&lt;/a&gt;.
12 months and 18 blog posts later, I would like to reflect on the past year and set some goals for 2023.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-cottonbro-studio-raise-glasses.j9FrFmP3_XVntA.webp&quot; srcset=&quot;/_astro/pexels-cottonbro-studio-raise-glasses.j9FrFmP3_srM2U.webp 640w, /_astro/pexels-cottonbro-studio-raise-glasses.j9FrFmP3_1KEw5d.webp 750w, /_astro/pexels-cottonbro-studio-raise-glasses.j9FrFmP3_Z1K24Q9.webp 828w, /_astro/pexels-cottonbro-studio-raise-glasses.j9FrFmP3_mkXyu.webp 1080w, /_astro/pexels-cottonbro-studio-raise-glasses.j9FrFmP3_ZNbe8s.webp 1280w, /_astro/pexels-cottonbro-studio-raise-glasses.j9FrFmP3_XVntA.webp 1600w&quot; alt=&quot;People celebrate and raise glasses of wine for a toast.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1069&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © cottonbro studio / pexels.com&lt;/p&gt;
&lt;p&gt;In general, I truly enjoy writing articles on a regular basis. I actually moved to Vienna in 2006 to study journalism. I’ve
also worked for some media organizations. But it wasn’t the right fit and I returned to coding. So, it really feels good
to kind of combine my two passions.&lt;/p&gt;
&lt;h2 id=&quot;what-ive-learned-this-year&quot;&gt;What I’ve Learned this Year&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;First of all, how to set up my own web server, manage a domain, create an SSL certificate, and so on. It felt good to leave
my comfort zone and try something new!&lt;/li&gt;
&lt;li&gt;How to automate my build and deploy workflow with &lt;a href=&quot;https://github.com/features/actions&quot;&gt;GitHub Actions&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;That I love to experiment with new features like the native &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt;  HTML element or
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;:focus-visible&lt;/code&gt;  CSS pseudo-class. It’s a great challenge to explain the concept and functionality
in a succinct way and provide useful demo code.&lt;/li&gt;
&lt;li&gt;I became familiar with &lt;a href=&quot;https://en.wikipedia.org/wiki/RSS&quot;&gt;RSS&lt;/a&gt; and learned how to provide my own RSS feed.
You can &lt;a href=&quot;https://www.oidaisdes.org/rss.xml&quot;&gt;subscribe here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;my-favorite-blog-posts&quot;&gt;My Favorite Blog Posts&lt;/h2&gt;
&lt;p&gt;It’s hard to pick my favorites among the 18 blog posts I’ve written this year. Therefore, I simply picked three posts about
topics that I deem especially relevant and exciting:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;/blog/common-aria-mistakes/&quot;&gt;“Common ARIA mistakes and how to avoid them”&lt;/a&gt;: It’s great that more and more
companies realize the importance of accessibility. Unfortunately, a lot of them go overboard with ARIA, sometimes making their website
even less accessible. I hope my blog post helps developers to better understand ARIA and avoid bad practices.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/cascade-layers-in-angular/&quot;&gt;“Using CSS Cascade Layers in Angular”&lt;/a&gt;: 2022 was a pretty great year for
CSS. Among the exciting new features adopted by modern browsers were CSS cascade layers. They’re a powerful tool to structure your
styles and avoid pesky conflicts due to specificity or order of appearance.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/lights-off-how-blind-users-navigate/&quot;&gt;“Lights Off! Experience how Blind Users navigate the Web”&lt;/a&gt;:
A few weeks ago, I gave a workshop on accessibility for a new client. Using my &lt;a href=&quot;https://alexlehner86.github.io/come-to-the-dark-side/home&quot;&gt;demo page&lt;/a&gt;,
I turned everything black and used a screen reader to navigate the website. The participants were truly amazed. One of them
said: &lt;span class=&quot;c-italic&quot;&gt;“I didn’t know that blind people can even use the internet!”&lt;/span&gt;  This taught me once more: People need to
experience the effects of disabilities to truly appreciate accessibility.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;goals-and-expectations-for-2023&quot;&gt;Goals and Expectations for 2023&lt;/h2&gt;
&lt;p&gt;As a web developer, I’m pretty excited for the new year. There’s a lot of new features on the horizon that should make our lives easier.
As a human being, I just hope for the terrible war in Ukraine to end. And for humanity to tackle climate change head-on!&lt;/p&gt;
&lt;p&gt;Anyway, here’s a list of goals for 2023 as well as topics I’d like to write about in the coming year:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I want to turn my social media interactions into &lt;a href=&quot;https://www.freecodecamp.org/news/how-to-use-webmentions-with-gatsby-beginners-guide/&quot;&gt;Webmentions&lt;/a&gt;
and display them on my blog.&lt;/li&gt;
&lt;li&gt;Flexbox or Grid? I want to deepen my knowledge about CSS layouts and experiment with new features like &lt;a href=&quot;https://ishadeed.com/article/learn-css-subgrid/&quot;&gt;CSS Subgrid&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;I’d like to improve my skills as a Requirements Engineer and Software Architect and write about what I’ve learned.&lt;/li&gt;
&lt;li&gt;Attending more developer conferences and maybe &lt;a href=&quot;https://www.freecodecamp.org/news/complete-guide-to-giving-your-first-conference-talk/&quot;&gt;giving a talk some day&lt;/a&gt;.
Hosting local events could be awesome too.&lt;/li&gt;
&lt;li&gt;Last but not least: Continue writing about accessibility.&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>accessibility</category><category>css</category><category>goals</category><category>html</category><category>retrospection</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_raise_glasses.jpg" length="0" type="image/jpeg"/></item><item><title>A Conversation with ChatGPT about Web Accessibility and Widespread Myths</title><link>https://www.oidaisdes.org/blog/chatgpt-accessibility-myths</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/chatgpt-accessibility-myths</guid><description>The artificial intelligence impresses with thoughtful and well composed answers. But it&apos;s not perfect.</description><pubDate>Sat, 10 Dec 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Artificial intelligence is gaining momentum. Be it self-driving cars, image generation, or chatbots – AI is more and more
a part of our everyday life. The conversational agent &lt;a href=&quot;https://openai.com/blog/chatgpt/&quot;&gt;ChatGPT&lt;/a&gt; shows just how advanced and
human-like AI can be.&lt;/p&gt;
&lt;p&gt;A lot of people have already shared their &lt;a href=&quot;https://mastodon.social/tags/ChatGPT&quot;&gt;conversations with the AI&lt;/a&gt;. It impresses with
thoughtful and well composed answers. But how would the chatbot react to rather pointed questions and biased opinions? To answer
this question, I just had a casual conversation with ChatGPT about some widespread accessibility myths.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-tara-winstead-robot-and-human.SFJ4qqCv_nau5r.webp&quot; srcset=&quot;/_astro/pexels-tara-winstead-robot-and-human.SFJ4qqCv_2cwYKl.webp 640w, /_astro/pexels-tara-winstead-robot-and-human.SFJ4qqCv_Z1W4HnS.webp 750w, /_astro/pexels-tara-winstead-robot-and-human.SFJ4qqCv_28ERfC.webp 828w, /_astro/pexels-tara-winstead-robot-and-human.SFJ4qqCv_2o5n6e.webp 1080w, /_astro/pexels-tara-winstead-robot-and-human.SFJ4qqCv_PSgwV.webp 1280w, /_astro/pexels-tara-winstead-robot-and-human.SFJ4qqCv_nau5r.webp 1600w&quot; alt=&quot;A human hand with an outstretched index finger approaches a robot hand.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1067&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Tara Winstead / pexels.com&lt;/p&gt;
&lt;p&gt;I split the conversation into several sections, starting with common questions, followed by four widespread myths about
accessibility. At the end of the article, I’ll share my thoughts about ChatGPT with you.&lt;/p&gt;
&lt;h2 id=&quot;my-conversation-with-chatgpt&quot;&gt;My conversation with ChatGPT&lt;/h2&gt;
&lt;p class=&quot;c-bold&quot;&gt; &lt;em&gt;Me:&lt;/em&gt; Hi ChatGPT! Everyone’s talking about web accessibility. Can you explain the concept in simple terms? &lt;/p&gt; 
&lt;p&gt;&lt;em&gt;ChatGPT:&lt;/em&gt; Sure! Web accessibility refers to the practice of making websites and web applications usable by people with disabilities. This includes people with visual, auditory, motor, and cognitive impairments, among others. The goal of web accessibility is to allow all users to access and use the content and features on a website, regardless of any disabilities they may have. This can be achieved by following a set of web accessibility guidelines and standards, such as the Web Content Accessibility Guidelines (WCAG) developed by the World Wide Web Consortium (W3C). These guidelines provide a set of specific criteria that websites and web applications should meet in order to be considered accessible. By following these guidelines, website developers and designers can ensure that their sites are usable by a wide range of users.&lt;/p&gt;
&lt;p class=&quot;c-bold&quot;&gt; &lt;em&gt;Me:&lt;/em&gt; I’m afraid that it will make web development more expensive and overly complicated. What is your opinion? &lt;/p&gt; 
&lt;p&gt;&lt;em&gt;ChatGPT:&lt;/em&gt; Incorporating web accessibility into the design and development of a website or web application does not have to be expensive or overly complicated. In fact, following web accessibility guidelines can often improve the overall user experience for all users, not just those with disabilities. For example, using clear and descriptive headings and labels on forms can make it easier for everyone to navigate and use the site, not just people with visual impairments. Additionally, using proper formatting and structure can make it easier for screen-reading software to interpret and read the content of a page, benefiting users who are blind or have low vision.&lt;/p&gt;
&lt;h2 id=&quot;myth-1-accessibility-benefits-only-a-small-group-of-people&quot;&gt;Myth #1: Accessibility benefits only a small group of people&lt;/h2&gt;
&lt;p class=&quot;c-bold&quot;&gt; &lt;em&gt;Me:&lt;/em&gt; Ok, sound’s great. What are the major benefits of an accessible website design? &lt;/p&gt; 
&lt;p&gt;&lt;em&gt;ChatGPT:&lt;/em&gt; There are several benefits to having an accessible website design. For users with disabilities, the most obvious benefit is the ability to access and use the content and features of the site. This can improve their overall experience of using the internet and allow them to participate in online activities that they may have previously been unable to do.&lt;/p&gt;
&lt;p&gt;In addition to benefiting users with disabilities, accessible website design can also provide benefits for businesses and organizations. For example, an accessible website can improve the search engine optimization (SEO) of the site, making it more visible to search engines and potentially increasing traffic to the site. An accessible website can also increase the potential audience for the site, since it can be used by a wider range of users. This can be especially beneficial for businesses and organizations that serve a diverse population or that are required by law to provide accessible services.&lt;/p&gt;
&lt;p&gt;Finally, incorporating web accessibility into the design of a website can also improve the overall user experience for all users, regardless of any disabilities they may have. This can lead to increased customer satisfaction and loyalty, as well as potential cost savings by reducing the need for customer support.&lt;/p&gt;
&lt;p class=&quot;c-bold&quot;&gt; &lt;em&gt;Me:&lt;/em&gt; I’m not sure. Doesn’t accessibility only benefit a small group of people? &lt;/p&gt; 
&lt;p&gt;&lt;em&gt;ChatGPT:&lt;/em&gt; While it is true that web accessibility primarily benefits users with disabilities, the potential audience for accessible websites is actually quite large. According to the World Health Organization, about 15% of the global population lives with some form of disability. This means that, in terms of sheer numbers, the potential audience for accessible websites is significant. Additionally, web accessibility can benefit a wide range of users with different types of disabilities, including visual, auditory, motor, and cognitive impairments, as well as users who may not have a permanent disability but who may have temporary impairments (such as a broken arm) or situational limitations (such as using a website on a mobile device while on the go). Overall, the potential audience for accessible websites is much larger than many people realize.&lt;/p&gt;
&lt;p class=&quot;c-bold&quot;&gt; &lt;em&gt;Me:&lt;/em&gt; You said that the potential audience for accessible websites was significant. But do people with disabilities really use the internet that much? &lt;/p&gt; 
&lt;p&gt;&lt;em&gt;ChatGPT:&lt;/em&gt; Yes, people with disabilities use the internet at similar rates to those without disabilities. A study by the Pew Research Center found that, in the United States, about 88% of adults with disabilities use the internet, compared to 91% of adults without disabilities. This indicates that people with disabilities are just as likely to use the internet as those without disabilities, and highlights the importance of ensuring that websites are accessible to all users.&lt;/p&gt;
&lt;p&gt;Additionally, the use of the internet by people with disabilities is likely to increase in the coming years, as advances in assistive technologies and the proliferation of mobile devices make it easier for people with disabilities to access the internet. This means that the potential audience for accessible websites will continue to grow, making web accessibility an increasingly important consideration for businesses and organizations.&lt;/p&gt;
&lt;h2 id=&quot;myth-2-accessibility-is-easy-and-should-be-the-last-step&quot;&gt;Myth #2: Accessibility is easy and should be the last step&lt;/h2&gt;
&lt;p class=&quot;c-bold&quot;&gt; &lt;em&gt;Me:&lt;/em&gt; Alright, let’s say I intend to create accessible websites. How hard can it be? I think accessibility can wait until the end of the development process after all of the other work is done. &lt;/p&gt; 
&lt;p&gt;&lt;em&gt;ChatGPT:&lt;/em&gt; While it is certainly possible to make a website accessible after it has been developed, it is generally much easier and more effective to incorporate web accessibility into the design and development process from the beginning. This is because accessibility is not just a matter of adding a few accessibility features at the end of the development process, but rather it involves considering accessibility at every stage of the design and development process.&lt;/p&gt;
&lt;p&gt;For example, when designing the layout and content of a website, it is important to consider how the site will be used by people with disabilities and to ensure that the design is usable by a wide range of users. This may involve using clear and descriptive headings and labels, providing alternative text for images, and using proper formatting and structure to make the content easily readable by screen-reading software.&lt;/p&gt;
&lt;p&gt;During the development process, it is also important to test the website to ensure that it meets web accessibility standards and guidelines. This can be done using a combination of automated testing tools and manual testing by individuals with disabilities or other specialized expertise. By incorporating accessibility into the design and development process from the beginning, it is much more likely that the final website will be accessible to all users.&lt;/p&gt;
&lt;p&gt;Overall, while it is possible to make a website accessible after it has been developed, it is much easier and more effective to consider web accessibility from the beginning. This can help to ensure that the website is usable by a wide range of users and meets the relevant accessibility standards and guidelines.&lt;/p&gt;
&lt;p class=&quot;c-bold&quot;&gt; &lt;em&gt;Me:&lt;/em&gt; But accessibility is so restrictive. Wouldn’t this hamper the creativity of web designers and developers? &lt;/p&gt; 
&lt;p&gt;&lt;em&gt;ChatGPT:&lt;/em&gt; Web accessibility does not have to restrict the creativity of web designers and developers. In fact, incorporating accessibility into the design and development process can often lead to more creative and effective solutions. This is because accessibility is not just about adding a few accessibility features to a website, but rather it involves considering the needs of all users, including those with disabilities, and finding ways to make the website usable and enjoyable for everyone.&lt;/p&gt;
&lt;p&gt;For example, when designing the layout and content of a website, web designers and developers can consider how the site will be used by people with disabilities and look for creative ways to make the site accessible and usable. This may involve using innovative design techniques, such as responsive design, to make the site accessible on a wide range of devices, or incorporating multimedia elements, such as videos or audio recordings, to make the content more accessible to users with visual or auditory impairments.&lt;/p&gt;
&lt;p&gt;Additionally, by incorporating accessibility into the design and development process, web designers and developers can often improve the overall user experience of the site for all users. This can lead to more creative and effective solutions that are not only accessible, but also engaging and enjoyable for all users.&lt;/p&gt;
&lt;p&gt;Overall, web accessibility does not have to restrict the creativity of web designers and developers. In fact, by considering the needs of all users and incorporating accessibility into the design and development process, web designers and developers can create websites that are not only accessible, but also innovative and effective.&lt;/p&gt;
&lt;h2 id=&quot;myth-3-accessibility-is-too-hard-and-expensive&quot;&gt;Myth #3: Accessibility is too hard and expensive&lt;/h2&gt;
&lt;p class=&quot;c-bold&quot;&gt; &lt;em&gt;Me:&lt;/em&gt; Still, there are so many different disabilities and assistive technologies to consider. Training employees and integrating accessibility into the whole development process is just too expensive. What do you think? &lt;/p&gt; 
&lt;p&gt;&lt;em&gt;ChatGPT:&lt;/em&gt; While it is true that training employees and incorporating accessibility into the design and development process can require some initial investment, the long-term benefits of web accessibility can outweigh the costs. For businesses and organizations, having an accessible website can increase the potential audience for the site, improve the search engine optimization (SEO) of the site, and lead to increased customer satisfaction and loyalty. This can result in significant financial benefits, such as increased sales or donations, and can help to offset the initial costs of implementing web accessibility.&lt;/p&gt;
&lt;p&gt;Additionally, there are many resources available to help businesses and organizations implement web accessibility, including training materials, guidelines and standards, and automated testing tools. These resources can help to make the process of implementing web accessibility more efficient and cost-effective.&lt;/p&gt;
&lt;p&gt;Overall, while implementing web accessibility can require some initial investment, the long-term benefits of an accessible website can outweigh the costs. By considering the needs of all users and incorporating accessibility into the design and development process, businesses and organizations can create websites that are usable by a wide range of users and that can provide significant financial benefits.&lt;/p&gt;
&lt;p class=&quot;c-bold&quot;&gt; &lt;em&gt;Me:&lt;/em&gt; Wouldn’t it be much cheaper to simply use an accessibility overlay? &lt;/p&gt; 
&lt;p&gt;&lt;em&gt;ChatGPT:&lt;/em&gt; An accessibility overlay is a tool that can be added to an existing website to make it more accessible to users with disabilities. While an accessibility overlay can provide some benefits, it is generally not as effective or efficient as incorporating accessibility into the design and development process from the beginning.&lt;/p&gt;
&lt;p&gt;One major disadvantage of using an accessibility overlay is that it only addresses the accessibility of the user interface (UI) of the website, not the underlying content or structure. This means that, while the UI may be more accessible with an overlay, the content of the site may still be difficult or impossible for users with disabilities to access. For example, an accessibility overlay may add alternative text to images, but if the images are not properly labeled or organized in the first place, they may still be difficult for users with visual impairments to understand.&lt;/p&gt;
&lt;p&gt;Additionally, using an accessibility overlay can be less efficient and more expensive than incorporating accessibility into the design and development process. This is because an accessibility overlay must be added to the site after it has been developed, which can require additional time and resources. In contrast, incorporating accessibility into the design and development process from the beginning can be more efficient and cost-effective, since it involves considering accessibility at every stage of the process.&lt;/p&gt;
&lt;p&gt;Overall, while an accessibility overlay can provide some benefits, it is generally not as effective or efficient as incorporating accessibility into the design and development process from the beginning. By considering the needs of all users and incorporating accessibility into the design and development process, businesses and organizations can create websites that are truly accessible to all users.&lt;/p&gt;
&lt;h2 id=&quot;myth-4-accessible-websites-are-ugly&quot;&gt;Myth #4: Accessible websites are ugly&lt;/h2&gt;
&lt;p class=&quot;c-bold&quot;&gt; &lt;em&gt;Me:&lt;/em&gt; Maybe you’re right and we should design for accessibility from the start. It’s just so hard to create accessible websites that look good. Most accessible websites are ugly and have poor visual design. &lt;/p&gt; 
&lt;p&gt;&lt;em&gt;ChatGPT:&lt;/em&gt; While it is true that some accessible websites may not have the same visual appeal as other websites, this does not have to be the case. Accessibility and visual design are not mutually exclusive, and it is possible to create websites that are both accessible and aesthetically pleasing.&lt;/p&gt;
&lt;p&gt;One way to achieve this is by following web accessibility guidelines and standards, such as the Web Content Accessibility Guidelines (WCAG) developed by the World Wide Web Consortium (W3C). These guidelines provide specific criteria that websites should meet in order to be considered accessible, while also allowing for flexibility in the design and layout of the site. This means that web designers and developers can use their creativity and expertise to create visually appealing websites that are also accessible to users with disabilities.&lt;/p&gt;
&lt;p&gt;Additionally, by considering the needs of all users, including those with disabilities, web designers and developers can create websites that are not only accessible and visually appealing, but also user-friendly and engaging for a wide range of users. This can lead to more effective and successful websites that are appreciated by all users, regardless of any disabilities they may have.&lt;/p&gt;
&lt;p&gt;Overall, while some accessible websites may not have the same visual appeal as other websites, it is possible to create websites that are both accessible and aesthetically pleasing. By following web accessibility guidelines and standards and considering the needs of all users, web designers and developers can create websites that are accessible, visually appealing, and user-friendly.&lt;/p&gt;
&lt;p class=&quot;c-bold&quot;&gt; &lt;em&gt;Me:&lt;/em&gt; What about underlining links? The WCAG success criterion 1.4.1 basically forces you to underline links, although it hurts the aesthetic appeal of a website. &lt;/p&gt; 
&lt;p&gt;&lt;em&gt;ChatGPT:&lt;/em&gt; The Web Content Accessibility Guidelines (WCAG) success criterion 1.4.1 states that “information and relationships conveyed through presentation can be programmatically determined or are available in text.” This means that any information or relationships that are conveyed visually through the presentation of a website, such as the location of a link, should also be available in text so that they can be understood by users with visual impairments who may not be able to see the visual presentation of the site.&lt;/p&gt;
&lt;p&gt;In the case of links, the WCAG success criterion 1.4.1 does not necessarily require that links be underlined, but it does require that the location of the link be clearly indicated in text. This can be achieved in a number of ways, such as by using a different color for links, by using a unique style or font for links, or by underlining links. The specific method used to indicate the location of a link is up to the web designer or developer, as long as it meets the requirements of the WCAG success criterion 1.4.1.&lt;/p&gt;
&lt;p&gt;Ultimately, the goal of the WCAG success criterion 1.4.1 is to ensure that the information and relationships conveyed through the presentation of a website are available in text so that they can be understood by users with visual impairments. While underlining links is one way to meet this criterion, there are other options available that can also provide good visual design while ensuring accessibility.&lt;/p&gt;
&lt;p class=&quot;c-bold&quot;&gt; &lt;em&gt;Me:&lt;/em&gt; You mixed up the criteria 1.3.1 and 1.4.1. The success criterion 1.4.1 actually states that “color is not used as the only visual means of conveying information, indicating an action, prompting a response, or distinguishing a visual element.” &lt;/p&gt; 
&lt;p&gt;&lt;em&gt;ChatGPT:&lt;/em&gt; I apologize if I mixed up the WCAG success criteria. The success criterion 1.4.1 that I mentioned does indeed state that “color is not used as the only visual means of conveying information, indicating an action, prompting a response, or distinguishing a visual element.” This means that websites should not use color as the only way to convey information or indicate an action, since this can make the content difficult or impossible to understand for users with visual impairments who may be unable to see the…&lt;/p&gt;
&lt;hr/&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In the end, ChatGPT suddenly broke off mid-sentence and became unresponsive. Maybe I overheated its artificial synapses, who knows.&lt;/p&gt;
&lt;p&gt;Overall, I’m impressed by the detailed and mostly accurate responses of ChatGPT. Talking to the AI, it actually feels
like you’re having a conversation with another human being. It’s kind of eerie.&lt;/p&gt;
&lt;p&gt;Of course, the AI isn’t perfect. After some time, the answers seem a little repetitive. Also, when I asked a specific question
about the &lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/use-of-color.html&quot;&gt;WCAG success criterion 1.4.1&lt;/a&gt;, ChatGPT responded with
erroneous information. I suppose that with more training, those errors will happen less and less often.&lt;/p&gt;
&lt;p&gt;Have you already had a conversation with ChatGPT? What was your experience like?&lt;/p&gt;</content:encoded><category>accessibility</category><category>AI</category><category>ChatGPT</category><category>design</category><category>disabilities</category><category>myths</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_robot_and_human.jpg" length="0" type="image/jpeg"/></item><item><title>3 Ways how Web Developers also benefit from Accessibility</title><link>https://www.oidaisdes.org/blog/3-ways-web-devs-benefit-accessibility</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/3-ways-web-devs-benefit-accessibility</guid><description>Semantic HTML is easy to read and maintain, keyboard operable by default, and works well with CSS.</description><pubDate>Sun, 27 Nov 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Web accessibility is an ethical duty and economically viable. You contribute to the inclusion of people with disabilities
and increase your potential client base. Still, as a web developer, you might be thinking: &lt;span class=&quot;c-italic&quot;&gt;“That’s great for
my company and society in general. But it means more work for me, argh!”&lt;/span&gt; &lt;/p&gt;
&lt;p&gt;I get it! Web accessibility can be overwhelming in the beginning. And yes, some stuff like
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions&quot;&gt;ARIA live regions&lt;/a&gt; actually increase
your workload slightly. But I want to let you in on a little secret: Accessibility will make your life as a web
developer easier and save you time in the long run!&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-thisisengineering-web-dev-workplace.vJsnZYGD_SB7eQ.webp&quot; srcset=&quot;/_astro/pexels-thisisengineering-web-dev-workplace.vJsnZYGD_Z1SLAFx.webp 640w, /_astro/pexels-thisisengineering-web-dev-workplace.vJsnZYGD_Z25pu2w.webp 750w, /_astro/pexels-thisisengineering-web-dev-workplace.vJsnZYGD_ZYq0eN.webp 828w, /_astro/pexels-thisisengineering-web-dev-workplace.vJsnZYGD_Ziwn3d.webp 1080w, /_astro/pexels-thisisengineering-web-dev-workplace.vJsnZYGD_Z22Quta.webp 1280w, /_astro/pexels-thisisengineering-web-dev-workplace.vJsnZYGD_SB7eQ.webp 1600w&quot; alt=&quot;A web developer sitting at her desk, facing three monitors. Lines of code are visible on a monitor.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1067&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © ThisIsEngineering / pexels.com&lt;/p&gt;
&lt;p&gt;You don’t believe me? Then keep on reading for three examples of the superior experience that accessibility brings.&lt;/p&gt;
&lt;h2 id=&quot;1-semantic-markup-is-easier-to-read-and-maintain&quot;&gt;1. Semantic markup is easier to read and maintain&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.w3schools.com/html/html5_semantic_elements.asp&quot;&gt;Semantic markup&lt;/a&gt; doesn’t only convey information about the meaning
of each element to assistive technologies. It also conveys this information to developers who need to read it, modify it or
refactor it.&lt;/p&gt;
&lt;p&gt;Imagine you’re joining a new team and getting familiar with the codebase. Would you be happy to find this kind of code?&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;fixed-header&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;banner&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;header-logo&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;img&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; aria-label&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;Logo Example Page&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;navigation&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; aria-label&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;Main Navigation&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;list&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;            &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;listitem&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; href&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Home&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;            &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;listitem&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; href&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;/about&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;About&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;main&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;heading&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; aria-level&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Best Pizza in Town&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;heading&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; aria-level&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;2&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Pizza Salami&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;pizza-salami&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;img&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; aria-label&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;Pizza with salami slices&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Some text&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;heading&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; aria-level&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;2&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Pizza Capricciosa&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;pizza-capri&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;img&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; aria-label&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;Pizza with baked ham, mushroom and artichoke&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Some text&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Damn, that’s a lot of &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;div&lt;/code&gt;  tags! Kinda hard to read. Well, wouldn’t you rather see this
HTML code instead:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;header&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;img&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; src&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;/header-logo.svg&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; alt&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;Logo Example Page&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;nav&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; aria-label&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;Main Navigation&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;            &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; href&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Home&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;            &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; href&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;/about&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;About&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;nav&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;header&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Best Pizza in Town&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Pizza Salami&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;img&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; src&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;/pizza-salami.jpg&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; alt&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;Pizza with salami slices&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Some text&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Pizza Capricciosa&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;img&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; src&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;/pizza-capri.jpg&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; alt&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;Pizza with baked ham, mushroom and artichoke&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Some text&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ah, that’s better! Now you can talk about the HTML code with your teammates in a meaningful way. Fun fact: Both code
examples would result in the same accessible experience for screen reader users. But only the second one is beneficial for
web developers.&lt;/p&gt;
&lt;p&gt;If you think that I exaggerated with my example of spaghetti code hell, let me tell you this: I’ve seen variations of
this on many websites out there. Which makes me sad.&lt;/p&gt;
&lt;h2 id=&quot;2-native-html-controls-are-keyboard-operable-by-default&quot;&gt;2. Native HTML controls are keyboard operable by default&lt;/h2&gt;
&lt;p&gt;HTML elements like &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;a&lt;/code&gt; , &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;button&lt;/code&gt; , &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;input type=“checkbox”&lt;/code&gt; ,
or &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;input type=“radio”&lt;/code&gt;  are all accessible by default. For example, users can navigate between buttons
using the tab key and activate their selection with the space or enter key.&lt;/p&gt;
&lt;p&gt;Imagine, for whatever reason, you want to implement a button using the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;div&lt;/code&gt;  element. To make this
abomination operable through a keyboard, you would have to do the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Apply &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;tabindex=“0”&lt;/code&gt;  to include the div in the tab order.&lt;/li&gt;
&lt;li&gt;Define a clearly visible focus indicator to convey when the div has focus.&lt;/li&gt;
&lt;li&gt;Implement a &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;keydown&lt;/code&gt;  event handler to activate the “button” when the space or enter key is pressed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here’s what you need to do using the native &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;button&lt;/code&gt;  element:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nothing!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Buttons are keyboard operable by default and trigger the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;click&lt;/code&gt;  event when the space or
enter key is pressed. And you can easily customize their styling with CSS. This is also true for most form elements.
Check out my &lt;a href=&quot;/blog/styling-accessible-web-forms/&quot;&gt;post about styling web forms&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;3-stateful-semantic-css-selectors-are-more-expressive-and-robust&quot;&gt;3. Stateful, semantic CSS selectors are more expressive and robust&lt;/h2&gt;
&lt;p&gt;You can leverage the semantic tag names and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA&quot;&gt;ARIA attributes&lt;/a&gt;
for expressive and easy to understand CSS selectors
like &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;header nav &amp;gt; ul { … }&lt;/code&gt;  or &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;button[aria-expanded=“true”] { … }&lt;/code&gt; .&lt;/p&gt;
&lt;p&gt;By interweaving your CSS rules with HTML tags and attributes, you no longer need to manage extra CSS classes dynamically
with JavaScript. You can concentrate on your business logic being reflected in the HTML code alone (e.g., by
setting &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;aria-expanded&lt;/code&gt;  to true or false).&lt;/p&gt;
&lt;p&gt;For more examples and an in-depth look at the concept, check out the
article &lt;a href=&quot;https://benmyers.dev/blog/semantic-selectors/&quot;&gt;“Style with Stateful, Semantic Selectors”&lt;/a&gt; by Ben Myers.&lt;/p&gt;
&lt;h2 id=&quot;useful-resources&quot;&gt;Useful Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3schools.com/html/html5_semantic_elements.asp&quot;&gt;HTML Semantic Elements (W3 Schools)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn/Accessibility/HTML&quot;&gt;HTML: A good basis for accessibility (MDN)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors&quot;&gt;CSS Attribute selectors (MDN)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 class=&quot;post-update-title&quot;&gt; &lt;span aria-hidden=&quot;true&quot;&gt;&amp;raquo;&amp;nbsp;&lt;/span&gt;Update on 12/16/2022 &lt;/h2&gt; 
&lt;p&gt;Revised section on stateful, semantic CSS selectors.&lt;/p&gt;</content:encoded><category>accessibility</category><category>cleanCode</category><category>css</category><category>developers</category><category>html</category><category>keyboard</category><category>web</category><category>webdev</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_web_dev_workplace.jpg" length="0" type="image/jpeg"/></item><item><title>Building Accessible Toggle Buttons in React</title><link>https://www.oidaisdes.org/blog/accessible-toggle-button</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/accessible-toggle-button</guid><description>Using the button element together with the switch role creates an accessible experience.</description><pubDate>Fri, 18 Nov 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Filter options, system preferences or a dark mode control – it’s very likely that you’ve come across a
toggle button before. At first sight, toggle buttons are simple: They allow the user to change a setting
between two states, usually “on” and “off”.&lt;/p&gt;
&lt;p&gt;Unfortunately, there’s no native HTML element for toggle buttons. Which is why there’s a lot of different
custom implementations roaming the internet. Some of them, you guessed it, totally inaccessible nightmares.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-gaby-tenda-dj-desk.clyO6qdc_15NsFy.webp&quot; srcset=&quot;/_astro/pexels-gaby-tenda-dj-desk.clyO6qdc_TC9U2.webp 640w, /_astro/pexels-gaby-tenda-dj-desk.clyO6qdc_Z2uGylT.webp 750w, /_astro/pexels-gaby-tenda-dj-desk.clyO6qdc_1vPR3C.webp 828w, /_astro/pexels-gaby-tenda-dj-desk.clyO6qdc_Z4fgAO.webp 1080w, /_astro/pexels-gaby-tenda-dj-desk.clyO6qdc_28KsKx.webp 1280w, /_astro/pexels-gaby-tenda-dj-desk.clyO6qdc_15NsFy.webp 1600w&quot; alt=&quot;A guy standing behind a DJ desk with many buttons and knobs.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1067&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Gaby Tenda / pexels.com&lt;/p&gt;
&lt;p&gt;I created a &lt;a href=&quot;https://alexlehner86.github.io/punk-api-beer-list/&quot;&gt;demo app&lt;/a&gt; in React with accessible
toggle buttons, which I’d like to show you. I’m not sure that it’s the perfect solution. So I’m
eager for some feedback.&lt;/p&gt;
&lt;h2 id=&quot;demo-beer-list-with-toggle-buttons&quot;&gt;Demo: Beer List with Toggle Buttons&lt;/h2&gt;
&lt;p&gt;In my demo, I display a list of beers. Users can switch between weak and strong beers using toggle
buttons. Give it a try:&lt;/p&gt;
&lt;iframe src=&quot;https://alexlehner86.github.io/punk-api-beer-list/&quot; title=&quot;Demo Page Beer List with weak/strong toggle button&quot; loading=&quot;lazy&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;If you inspect the code, you’ll see that I used a group of buttons and applied
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;switch&lt;/code&gt;  role to them. Before we take a closer look at the technical details,
I want to explain what I wanted to achieve with the control.&lt;/p&gt;
&lt;h2 id=&quot;goals-and-requirements&quot;&gt;Goals and Requirements&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;The control should clearly convey its functionality, both visually and to assistive technologies.&lt;/li&gt;
&lt;li&gt;It should indicate its current state, both visually and to assistive technologies.&lt;/li&gt;
&lt;li&gt;Users should be able to operate the control with the keyboard alone, duh!&lt;/li&gt;
&lt;li&gt;Only one option (“weak” or “strong”) can be active at one time. If one option is switched on,
the other one is switched off.&lt;/li&gt;
&lt;li&gt;Switching between the two options should be a deliberate act by the user and not happen by accident.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;semantic-markup-and-keyboard-operability&quot;&gt;Semantic Markup and Keyboard Operability&lt;/h2&gt;
&lt;p&gt;You could use radio buttons and change their styling with CSS. I decided not to use them because they’re
automatically selected on focus (not what I want!) and they’re standard form elements. Web forms should
not trigger a change of context until hitting the submit button.&lt;/p&gt;
&lt;p&gt;So, I decided to use a &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;button&lt;/code&gt;  element for each selectable option (“weak” and “strong”)
and apply the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;switch&lt;/code&gt;  role. The &lt;a href=&quot;https://www.w3.org/TR/wai-aria-1.2/#switch&quot;&gt;specification&lt;/a&gt;
for the role states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A type of checkbox that represents on/off values, as opposed to checked/unchecked values.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;My &lt;a href=&quot;https://github.com/alexlehner86/punk-api-beer-list/tree/main/src/components/TwoStateSwitch&quot;&gt;React component&lt;/a&gt;
contains a toggle button for each option. This way, I can label them individually and clearly convey their
state (on or off). Furthermore, the two buttons are grouped inside a &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;section&lt;/code&gt;  element
with the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;group&lt;/code&gt;  role. Take a look at the JSX code:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; className&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;styles&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;container&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;group&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; aria-label&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;switchLabel&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;switchLabel&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; className&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;styles&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;switchWrapper&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            type&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;button&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            role&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;switch&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            aria-checked&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;selectedState&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; === &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;stateValues&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            onClick&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;toggleSwitch&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;            {&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;stateLabels&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            type&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;button&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            role&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;switch&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            aria-checked&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;selectedState&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; === &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;stateValues&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            onClick&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;toggleSwitch&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;            {&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;stateLabels&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Users can focus the buttons with the tab key and toggle the state with the space or enter key.&lt;/p&gt;
&lt;h2 id=&quot;custom-styling-with-css&quot;&gt;Custom Styling with CSS&lt;/h2&gt;
&lt;p&gt;The toggle buttons’ styling visually conveys their functionality and current state. When an option is
selected, I invert its colors and add a vertical line using the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;::after&lt;/code&gt;  pseudo-element.
Here’s an excerpt from my component’s SCSS file:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;/* Invert background and text colors */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;aria-checked&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    background&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;--light-black&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    color&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;white&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;/* Add vertical line to highlight selected option */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;aria-checked&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;:after&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    content&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    position&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;absolute&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    bottom&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.2em&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    top&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.2em&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;aria-checked&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;:first-of-type:after&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    right&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.2em&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    border-right&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.3em&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; solid&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;--primary-color&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;aria-checked&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;:last-of-type:after&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    left&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.2em&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    border-left&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.3em&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; solid&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;--primary-color&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;feedback&quot;&gt;Feedback&lt;/h2&gt;
&lt;p&gt;So, that’s it. My proposed solution for accessible toggle buttons. Do you love it, do you hate it?
Hit me up on Twitter, Mastodon or GitHub!&lt;/p&gt;
&lt;h2 id=&quot;useful-resources&quot;&gt;Useful Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/switch_role&quot;&gt;ARIA: switch role (MDN)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/wai-aria-1.2/#switch&quot;&gt;WAI-ARIA 1.2 (specification)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://joshcollinsworth.com/blog/accessible-toggle-buttons&quot;&gt;Building Accessible Toggle Buttons (Alternative Approach by Josh Collinsworth)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>accessibility</category><category>aria</category><category>button</category><category>css</category><category>html</category><category>keyboard</category><category>react</category><category>toggle</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_dj_desk.jpg" length="0" type="image/jpeg"/></item><item><title>Common ARIA mistakes and how to avoid them</title><link>https://www.oidaisdes.org/blog/common-aria-mistakes</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/common-aria-mistakes</guid><description>ARIA roles and attributes can make your website more accessible, if you know what you&apos;re doing.</description><pubDate>Mon, 17 Oct 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;So you want to make your website more accessible? Great! And you’ve heard about
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA&quot;&gt;ARIA&lt;/a&gt;, which stands for Accessible Rich Internet
Applications. Just slap some ARIA attributes on all HTML elements and your page is accessible? Wrong!&lt;/p&gt;
&lt;p&gt;If you don’t know what you’re doing, you’ll end up making your website even less accessible! There’s a reason why
the first rule of ARIA is: &lt;strong&gt;No ARIA is better than Bad ARIA!&lt;/strong&gt; Use native HTML elements and attributes
with the semantics and behaviour you require.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-ketut-subiyanto-confused-couple.BugMF6Zv_1wXcuY.webp&quot; srcset=&quot;/_astro/pexels-ketut-subiyanto-confused-couple.BugMF6Zv_145ewT.webp 640w, /_astro/pexels-ketut-subiyanto-confused-couple.BugMF6Zv_ZU0eR2.webp 750w, /_astro/pexels-ketut-subiyanto-confused-couple.BugMF6Zv_1ChllD.webp 828w, /_astro/pexels-ketut-subiyanto-confused-couple.BugMF6Zv_1NmJIP.webp 1080w, /_astro/pexels-ketut-subiyanto-confused-couple.BugMF6Zv_Z1heA8U.webp 1280w, /_astro/pexels-ketut-subiyanto-confused-couple.BugMF6Zv_1wXcuY.webp 1600w&quot; alt=&quot;A woman sits on the floor, balancing a laptop on her knees. She looks confused at the man next to her.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1014&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Ketut Subiyanto / pexels.com&lt;/p&gt;
&lt;p&gt;Let’s take a look at use cases for ARIA and common mistakes you should avoid.&lt;/p&gt;
&lt;h2 id=&quot;aria-what-is-it-good-for&quot;&gt;ARIA, what is it good for?&lt;/h2&gt;
&lt;p&gt;ARIA is a set of &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles&quot;&gt;roles&lt;/a&gt; and
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes&quot;&gt;attributes&lt;/a&gt; that can help you to make
web content more accessible to people with disabilities. The latest version &lt;a href=&quot;https://www.w3.org/TR/wai-aria-1.2/&quot;&gt;WAI-ARIA 1.2&lt;/a&gt;
was released by the W3C in December 2021.&lt;/p&gt;
&lt;p&gt;Persons with certain types of disabilities use assistive technologies to interact with web content. For example, blind users
navigate websites with the help of screen readers. People with motor disabilities may rely on speech recognition software
to interact with a website.&lt;/p&gt;
&lt;p&gt;Web developers can use ARIA roles and attributes to convey semantics of the content to users of assistive technologies.
You can set &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;aria-expanded&lt;/code&gt;  on an element to indicate if a control is expanded or collapsed.
The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;aria-selected&lt;/code&gt;  attribute indicates if, e.g., a tab is currently selected or not.&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;h3&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;button&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; aria-expanded&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; aria-controls&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;section1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;header1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        Personal Information&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;h3&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;section1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;region&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; aria-labelledby&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;header1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;    &amp;lt;!-- Panel content that is shown/hidden via button --&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In general, only use ARIA for custom widgets like, e.g., an expansion panel. Check out the
&lt;a href=&quot;https://www.w3.org/WAI/ARIA/apg/&quot;&gt;ARIA Authoring Practices Guide&lt;/a&gt;, which describes how to apply accessibility semantics
to common design patterns and widgets.&lt;/p&gt;
&lt;h2 id=&quot;bad-aria-practices&quot;&gt;Bad ARIA practices&lt;/h2&gt;
&lt;p&gt;I’ve audited hundreds of websites for accessibility. One thing I’ve noticed is: Many web developers apparently have no
idea what they’re doing! They clutter the DOM with ARIA roles and attributes as if there was no tomorrow. I’ll show you
some of the most common mistakes I’ve encountered.&lt;/p&gt;
&lt;h3 id=&quot;using-aria-hiddentrue-on-a-focusable-element&quot;&gt;Using &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;aria-hidden=“true”&lt;/code&gt;  on a focusable element&lt;/h3&gt;
&lt;p&gt;ARIA gives you full control over the &lt;a href=&quot;https://web.dev/the-accessibility-tree/&quot;&gt;accessibility tree&lt;/a&gt;, which is a modified
version of the DOM that is presented to assistive technolgies. The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;aria-hidden&lt;/code&gt;  attribute allows
you to remove an element from the accessibility tree and thereby hide it from screen reader users.&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; href&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;https://www.stuff.com&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; aria-hidden&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Interesting Stuff&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The problem is: Removing a focusable element like a link from the accessibility tree does not remove it from tab order.
A screen reader user tabbing through the website will arrive at the link and hear “empty” or something similar. Please,
don’t do this!&lt;/p&gt;
&lt;h3 id=&quot;setting-an-aria-label-different-from-the-visible-label&quot;&gt;Setting an &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;aria-label&lt;/code&gt;  different from the visible label&lt;/h3&gt;
&lt;p&gt;Imagine you’re a university student in Vienna and want to register for a lecture online. Because of your
&lt;a href=&quot;https://en.wikipedia.org/wiki/Tremor&quot;&gt;hand-tremor&lt;/a&gt;, you use voice recognition software to operate the website. You
encounter the following web form in German:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; action&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;form-field&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;firstname&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Vorname&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;text&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; aria-label&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;First Name&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;firstname&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;firstname&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;form-field&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;lastname&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Nachname&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;text&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; aria-label&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;Last Name&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;lastname&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;lastname&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;    &amp;lt;!-- Other fields --&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To fill out the form, you want to focus on the first input field with the visible label &lt;span lang=&quot;de&quot;&gt;“Vorname”&lt;/span&gt;.
Therefore, you speak the voice command &lt;em lang=&quot;de&quot;&gt;“Vorname klicken”&lt;/em&gt; (in German), but nothing happens.
What is going on?&lt;/p&gt;
&lt;p&gt;As the code above shows, the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;label&lt;/code&gt;  element is programmatically associated with the input field using
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;for&lt;/code&gt;  attribute. Unfortunately, the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;aria-label&lt;/code&gt;  attribute overwrites
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;input&lt;/code&gt;  element’s accessible name with “First Name”. This means, that the control’s name does not
include the visible label.&lt;/p&gt;
&lt;p&gt;So the form is not easy to operate for voice recognition users and it also represents a clear
&lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/label-in-name.html&quot;&gt;WCAG violation&lt;/a&gt;. Fun fact: This is an actual example
from the German website of a large university in Vienna.&lt;/p&gt;
&lt;h3 id=&quot;the-aria-labelledby-attribute-references-an-id-that-doesnt-exist&quot;&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;aria-labelledby&lt;/code&gt;  attribute references an ID that doesn’t exist&lt;/h3&gt;
&lt;p&gt;You can use the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;aria-labelledby&lt;/code&gt;  attribute to label an element by referencing another element. Its
value should be a list of one or more ID values referencing the elements that label the current element. Here’s an example:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;nav&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; aria-labelledby&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;sidenav-title&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;sidenav-title&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Related Content&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;        &amp;lt;!-- List of links --&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;nav&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If there were no element with the id “sidenav-title”, then the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;nav&lt;/code&gt;  element would have no label.
This would result in a less than optimal experience for screen reader users. Therefore, always check that the elements
referenced by &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;aria-labelledby&lt;/code&gt;  are present in the DOM.&lt;/p&gt;
&lt;h3 id=&quot;navigation-menu-with-rolemenubar-or-rolemenu&quot;&gt;Navigation Menu with &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;role=“menubar”&lt;/code&gt;  or &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;role=“menu”&lt;/code&gt; &lt;/h3&gt;
&lt;p&gt;Many websites include site navigation that is styled to look like a menubar with expandable sections. Because of the
visual appearance, a lot of web developers think that they should apply the following semantic roles:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menubar&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;none&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menuitem&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; href&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Home&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;none&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menuitem&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; aria-haspopup&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; aria-expanded&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; href&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;#&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;About&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menu&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; aria-label&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;About&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;            &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;none&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;                &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menuitem&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; href&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;/overview&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Overview&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;            &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;            &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;none&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;                &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;menuitem&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; href&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;/administration&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Administration&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;            &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The problem with this markup is the expectations it creates. The roles &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;menubar&lt;/code&gt; 
and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;menu&lt;/code&gt;  should be used for menu widgets that offer a list of choices to the user,
such as a set of actions. These menus should behave like native operating system menus, which means: They
should &lt;a href=&quot;https://www.w3.org/WAI/ARIA/apg/patterns/menu/&quot;&gt;implement a specific set of keyboard interactions&lt;/a&gt;,
including navigation with arrow keys.&lt;/p&gt;
&lt;p&gt;If you create a site navigation with, e.g., &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;role=“menubar”&lt;/code&gt; , then screen reader users
will expect to navigate the menu with the arrow keys. When this doesn’t work, they’ll be confused.
A better alternative is to implement the
&lt;a href=&quot;https://www.w3.org/WAI/ARIA/apg/example-index/disclosure/disclosure-navigation.html&quot;&gt;disclosure pattern&lt;/a&gt; for
site navigation with expandable groups.&lt;/p&gt;
&lt;h2 id=&quot;basic-rules-for-using-aria&quot;&gt;Basic rules for using ARIA&lt;/h2&gt;
&lt;p&gt;As we’ve seen, a lot can go wrong with ARIA. Here’s a list of basic rules that will make your life easier:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go for native HTML elements first.&lt;/li&gt;
&lt;li&gt;Do not change native semantics, unless you really have to.&lt;/li&gt;
&lt;li&gt;Use ARIA for custom widgets and strictly follow the Authoring Practices Guide.&lt;/li&gt;
&lt;li&gt;All interactive ARIA controls must be usable with the keyboard.&lt;/li&gt;
&lt;li&gt;Test your code with assistive technologies like screen readers and voice recognition software.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;useful-resources&quot;&gt;Useful Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA&quot;&gt;ARIA (MDN)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/WAI/ARIA/apg/&quot;&gt;ARIA Authoring Practices Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/the-accessibility-tree/&quot;&gt;The Accessibility Tree&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>accessibility</category><category>aria</category><category>html</category><category>mistakes</category><category>screenreader</category><category>voiceInput</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_confused_couple.jpg" length="0" type="image/jpeg"/></item><item><title>CSS tweaks for better visibility in Forced Colors Mode</title><link>https://www.oidaisdes.org/blog/forced-colors-mode</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/forced-colors-mode</guid><description>Find out how forced colors mode works for websites and how to improve the user experience.</description><pubDate>Tue, 27 Sep 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;High contrast between text and its background benefits everyone. Be it people with low vision or anyone looking
at the screen in the glaring sun. That’s why &lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html&quot;&gt;WCAG&lt;/a&gt;
has minimum requirements for contrast of text and UI components.&lt;/p&gt;
&lt;p&gt;For some visually impaired users, this is not enough. They need specific color themes with high contrast to increase
text legibility and improve readability. Assistive technology like
&lt;a href=&quot;https://assistivlabs.com/assistive-tech/display/high-contrast-mode&quot;&gt;High Contrast Mode&lt;/a&gt; on Windows can actively
change a website’s colors to accomodate users with limited vision.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-steve-johnson-color-palette.Ch_oZIFL_1Vb6ee.webp&quot; srcset=&quot;/_astro/pexels-steve-johnson-color-palette.Ch_oZIFL_2oGe30.webp 640w, /_astro/pexels-steve-johnson-color-palette.Ch_oZIFL_12HXOW.webp 750w, /_astro/pexels-steve-johnson-color-palette.Ch_oZIFL_Kaspr.webp 828w, /_astro/pexels-steve-johnson-color-palette.Ch_oZIFL_Z2npGXf.webp 1080w, /_astro/pexels-steve-johnson-color-palette.Ch_oZIFL_1LqmDf.webp 1280w, /_astro/pexels-steve-johnson-color-palette.Ch_oZIFL_1Vb6ee.webp 1600w&quot; alt=&quot;A mix of different colors on a canvas.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1067&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Steve Johnson / pexels.com&lt;/p&gt;
&lt;p&gt;I’ll show you how forced colors mode works for websites and how to improve the user experience with some CSS tweaks.&lt;/p&gt;
&lt;h2 id=&quot;how-does-forced-colors-mode-work&quot;&gt;How does Forced Colors Mode work?&lt;/h2&gt;
&lt;p&gt;Forced colors mode is a cross-browser standard defined in
&lt;a href=&quot;https://www.w3.org/TR/css-color-adjust-1/#forced&quot;&gt;CSS Color Adjustment Module Level 1&lt;/a&gt;. Operating systems
should provide built-in color themes and allow users to customize their own themes.&lt;/p&gt;
&lt;p&gt;The specification states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When &lt;strong&gt;forced colors mode&lt;/strong&gt; is active (…), colors on the element are force-adjusted to the user’s preferred color palette.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This means that color values are replaced with &lt;a href=&quot;https://www.w3.org/TR/css-color-4/#css-system-colors&quot;&gt;system colors&lt;/a&gt; to match the
defined theme. Among the affected CSS properties are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;color&lt;/code&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;background-color&lt;/code&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;border-color&lt;/code&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;outline-color&lt;/code&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;fill&lt;/code&gt; 
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Other properties like &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;box-shadow&lt;/code&gt;  and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;text-shadow&lt;/code&gt;  are set
to &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;none&lt;/code&gt; . To give you an example, this is what my blog looks like in forced colors
mode with a dark theme:&lt;/p&gt;
&lt;img src=&quot;/_astro/oida-is-des-org-blog-high-contrast.ZXGCKf-4_Z21pn8O.webp&quot; srcset=&quot;/_astro/oida-is-des-org-blog-high-contrast.ZXGCKf-4_JgJpj.webp 640w, /_astro/oida-is-des-org-blog-high-contrast.ZXGCKf-4_Z1LhuaD.webp 750w, /_astro/oida-is-des-org-blog-high-contrast.ZXGCKf-4_15wQ7O.webp 828w, /_astro/oida-is-des-org-blog-high-contrast.ZXGCKf-4_Z21pn8O.webp 934w&quot; alt=&quot;A sub page of &apos;Oida, is des org&apos; with forced colors mode active.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 934px) 934px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;934&quot; height=&quot;675&quot;&gt;
&lt;h2 id=&quot;how-to-test-forced-colors-mode&quot;&gt;How to test forced colors mode&lt;/h2&gt;
&lt;p&gt;You can use the
&lt;a href=&quot;https://developer.chrome.com/docs/devtools/rendering/emulate-css/#emulate-css-media-feature-forced-colors&quot;&gt;developer tools in Chrome and Edge&lt;/a&gt;
to emulate forced colors mode and check the visibility of your content:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the Rendering tab.&lt;/li&gt;
&lt;li&gt;Under “Emulate CSS media feature forced-colors”, select “forced-colors: active” from the dropdown list.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;the-forced-colors-media-query&quot;&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;forced-colors&lt;/code&gt;  media query&lt;/h2&gt;
&lt;p&gt;Use the media query &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;forced-colors&lt;/code&gt;  to apply certain styling only when forced colors mode
is active. For example, I’ve included a SVG pattern in the background of my blog using
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;background-image&lt;/code&gt;  property:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;#___gatsby&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    background-image&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;data:image/svg+xml...&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    background-attachment&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;fixed&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    background-size&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;cover&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using the media query, I remove the background image when forced colors mode is active:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@media&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; (forced-colors: active) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;    #___gatsby&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        background-image&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;none&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another useful CSS property is &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;forced-color-adjust&lt;/code&gt; . It allows you to opt certain elements
out of forced colors mode and optimize its styling yourself.&lt;/p&gt;
&lt;h2 id=&quot;transparent-borders-and-outlines&quot;&gt;Transparent borders and outlines&lt;/h2&gt;
&lt;p&gt;Web layouts often communicate the boundary of an element with a different &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;background-color&lt;/code&gt; 
or via &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;box-shadow&lt;/code&gt; . In forced colors mode, all elements have the same background color and shadows
are removed. This lack of clear boundaries between elements can be confusing for users.&lt;/p&gt;
&lt;p&gt;But don’t despair! There’s a clever solution for this problem: Set a border with the color &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;transparent&lt;/code&gt; .
When forced colors mode replaces the color value, the border becomes visible and communicates the boundaries of
the element:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;section.info-card&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    border&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1px&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; solid&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; transparent&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can use the same logic to ensure visible focus indicators in forced colors mode. Usually, browsers add an outline to
a link or button when it receives focus. It’s totally fine to remove the outline with &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;outline: none&lt;/code&gt; 
if you provide a different focus indicator, e.g., a different background color. As this won’t work in forced colors mode,
the better solution is to make the outline transparent:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;a:focus&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    background&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;--primary&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    color&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;--white&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;    /* Provide visible focus indicator in forced colors mode */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    outline&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;2px&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; solid&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; transparent&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There’s even more great CSS techniques to fix common accessibility issues in forced colors mode. Please watch the
video &lt;a href=&quot;https://www.youtube.com/watch?v=vlx70ABSAP0&quot;&gt;“Practical Styling in Forced Colors Mode”&lt;/a&gt; by Mike Herchel.&lt;/p&gt;
&lt;h2 id=&quot;useful-resources&quot;&gt;Useful Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/@media/forced-colors&quot;&gt;forced-colors (MDN)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/forced-color-adjust&quot;&gt;forced-color-adjust (MDN)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.smashingmagazine.com/2022/03/windows-high-contrast-colors-mode-css-custom-properties/&quot;&gt;Windows High Contrast Mode, Forced Colors Mode And CSS Custom Properties&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>accessibility</category><category>css</category><category>color</category><category>contrast</category><category>eyesight</category><category>visibility</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_color_palette.jpg" length="0" type="image/jpeg"/></item><item><title>Using CSS Cascade Layers in Angular</title><link>https://www.oidaisdes.org/blog/cascade-layers-in-angular</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/cascade-layers-in-angular</guid><description>Structure your styles and avoid pesky conflicts with specificity or order of appearance.</description><pubDate>Mon, 05 Sep 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;We’ve all been there: You define a new CSS rule, rebuild your web application, and check the browser to see that
your styling isn’t being applied. Come on!&lt;/p&gt;
&lt;p&gt;Many times, there’s a conflict with another CSS rule that has &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity&quot;&gt;higher specificity&lt;/a&gt;.
Maybe you’ve included a third-party library that defines style rules that conflict with your own.&lt;/p&gt;
&lt;p&gt;Luckily for us web developers, a new CSS feature comes to the rescue: &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;CSS Cascade Layers&lt;/code&gt; .
They allow us to strictly layer our styles and avoid conflicts. I’ll show you how to use them in an Angular web
application with &lt;a href=&quot;https://sass-lang.com/&quot;&gt;SCSS&lt;/a&gt;.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-dalila-dalprat-cake.Ca7jM4DH_1gbhYa.webp&quot; srcset=&quot;/_astro/pexels-dalila-dalprat-cake.Ca7jM4DH_ZTgBU7.webp 640w, /_astro/pexels-dalila-dalprat-cake.Ca7jM4DH_Z20UaSl.webp 750w, /_astro/pexels-dalila-dalprat-cake.Ca7jM4DH_2uANGF.webp 828w, /_astro/pexels-dalila-dalprat-cake.Ca7jM4DH_Z1iUOBg.webp 1080w, /_astro/pexels-dalila-dalprat-cake.Ca7jM4DH_ZOG1Al.webp 1280w, /_astro/pexels-dalila-dalprat-cake.Ca7jM4DH_1gbhYa.webp 1600w&quot; alt=&quot;A cake with several visible layers.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1067&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Dalila Dalprat / pexels.com&lt;/p&gt;
&lt;h2 id=&quot;what-are-cascade-layers&quot;&gt;What are Cascade Layers?&lt;/h2&gt;
&lt;p&gt;CSS Cascade Layers give authors more control over the cascade, which is to say: The way the browser chooses which
styling rules to apply for a specific HTML element.&lt;/p&gt;
&lt;p&gt;The new feature is defined in the CSS Module &lt;a href=&quot;https://drafts.csswg.org/css-cascade-5/#layering&quot;&gt;Cascading and Inheritance Level 5&lt;/a&gt;.
Although the document has only “Editor’s Draft” status, cascade layers are already supported
by &lt;a href=&quot;https://caniuse.com/css-cascade-layers&quot;&gt;all modern browsers&lt;/a&gt;. The document states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Cascade layers&lt;/strong&gt; provide a structured way to organize and balance concerns within a single origin. Rules within a single cascade layer cascade together, without interleaving with style rules outside the layer.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This means that we can establish various layers – starting with low-priority styles like resets and third-party libraries,
up to high-priority styles like components and utilities. Conflicts between layers are always resolved by using the
higher-priority layer styles.&lt;/p&gt;
&lt;p&gt;If we look at the steps of the cascade, we see that layers are evaluated before specificity and order of appearance are
taken into account:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Origin and importance (&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;!important&lt;/code&gt; )&lt;/li&gt;
&lt;li&gt;Context&lt;/li&gt;
&lt;li&gt;Element Attached styles&lt;/li&gt;
&lt;li&gt;Layers&lt;/li&gt;
&lt;li&gt;Specificity&lt;/li&gt;
&lt;li&gt;Order of Appearance&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Please watch the video &lt;a href=&quot;https://www.youtube.com/watch?v=zEPXyqj7pEA&quot;&gt;“The CSS Cascade, a deep dive”&lt;/a&gt; by Bramus Van Damme
if you want to explore the CSS cascade in more detail.&lt;/p&gt;
&lt;h2 id=&quot;the-layer-rule&quot;&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@layer&lt;/code&gt;  rule&lt;/h2&gt;
&lt;p&gt;In general, we create a named cascade layer and define rules within this layer using
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@layer&lt;/code&gt;  rule:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@layer&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; my-layer {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    // CSS rules&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also create a named cascade layer without assigning any styles. This is used to determine the hierarchy of your
layers. A best practice is to first define the hierarchy of your layers in a single &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;@layer&lt;/code&gt; 
statement, followed by the style rules separated into these layers.&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@layer&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; my-layer-1, my-layer-2;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@layer&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; my-layer-1 {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    // CSS rules&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@layer&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; my-layer-2 {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    // CSS rules&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Any styles not in a layer are gathered together and placed into a single anonymous layer that comes after all the declared
layers. This means that any styles declared outside of a layer will always override styles declared in a layer.&lt;/p&gt;
&lt;p&gt;I won’t get into all the details about cascade layers. Please read the great article
&lt;a href=&quot;https://css-tricks.com/css-cascade-layers/&quot;&gt;“A Complete Guide to CSS Cascade Layers”&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;demo-application-with-angular-and-scss&quot;&gt;Demo Application with Angular and SCSS&lt;/h2&gt;
&lt;p&gt;I’ve created an application with &lt;a href=&quot;https://angular.io/&quot;&gt;Angular 14&lt;/a&gt; and &lt;a href=&quot;https://leafletjs.com/&quot;&gt;Leaflet&lt;/a&gt;
to display an interactive map. I use SCSS for styling, as it offers great features like placeholders and mixins. Check out
&lt;a href=&quot;https://github.com/alexlehner86/cascade-layers-angular-demo&quot;&gt;my demo code here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;My goal for the application is simple: I want to make sure that my styling for individual components is always applied.
They should take precedence over, e.g., CSS resets and library styles. For this purpose, I’ve created several cascade layers
in the main &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;styles.scss&lt;/code&gt;  file of my application:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@use&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; &amp;quot;sass:meta&amp;quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@layer&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; reset, thirdparty, overrides;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@layer&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; reset {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;    @include&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; meta.load-css(&amp;quot;layers/reset/normalize&amp;quot;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@layer&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; thirdparty {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;    @include&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; meta.load-css(&amp;quot;node_modules/leaflet/dist/leaflet.css&amp;quot;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@layer&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; overrides {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;    @include&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; meta.load-css(&amp;quot;layers/overrides/leaflet&amp;quot;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I use the SASS function &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;load-css&lt;/code&gt;  to load the CSS from another SCSS file and include it as part
of a cascade layer. I put all user agent style resets in the lowest-priority layer, followed by the layer for the basic
styling of the interactive leaflet map and a layer for global overrides.&lt;/p&gt;
&lt;p&gt;I don’t define cascade layers for the styles of specific components declared in their own SCSS file. All these styles are
automatically put into an anonymous layer that receives the highest priority. Let’s look at a specific example.&lt;/p&gt;
&lt;h2 id=&quot;styling-a-map-popup&quot;&gt;Styling a Map Popup&lt;/h2&gt;
&lt;p&gt;My demo app lists my 5 favorite places in Vienna. They are marked on an interactive leaflet map. When you click on a marker,
a popup opens. The HTML template &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;fav-place-popup.component.html&lt;/code&gt;  of the popup component looks
like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;{{data.name}}&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; *ngFor&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;let desc of data.description&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;{{desc}}&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’ve applied the following styles in &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;fav-place-popup.component.scss&lt;/code&gt; :&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    font-size&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.8rem&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    margin&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.5em&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At the same time, the leaflet library defines the following styles for paragraphs inside of map popups:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;.leaflet-popup-content&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt; p&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    margin&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;18px&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Thanks to my established order of cascade layers, I don’t have to worry about leaflet’s styles
for &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;.leaflet-popup-content p&lt;/code&gt;  interfering with my component styles for &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;p&lt;/code&gt; .
At the same time, Angular’s &lt;a href=&quot;https://angular.io/guide/view-encapsulation&quot;&gt;view encapsulation&lt;/a&gt; ensures that my
component’s styles are not applied to all paragraphs in my application. Sweet!&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I love cascade layers! They’re a powerful tool to structure your styles and avoid pesky conflicts due to specificity
or order of appearance.&lt;/p&gt;
&lt;p&gt;There’s one problem remaining: Some Angular libraries (e.g. &lt;a href=&quot;https://material.angular.io/&quot;&gt;Angular Material&lt;/a&gt;) automatically
add styles to the HTML document’s &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;head&lt;/code&gt;  tag. So far, I haven’t found a way to put these styles in
a cascade layer of my choice. I hope this issue will be addressed in the future.&lt;/p&gt;</content:encoded><category>angular</category><category>css</category><category>design</category><category>scss</category><category>specificity</category><category>structure</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_cake.jpg" length="0" type="image/jpeg"/></item><item><title>Why you should use the Native Dialog Element</title><link>https://www.oidaisdes.org/blog/native-dialog-element</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/native-dialog-element</guid><description>The dialog element is easy to use and accessible by default, apart from some minor issues.</description><pubDate>Tue, 19 Jul 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;We’re all familiar with dialogs. From simple prompts for confirming an action to content-heavy windows —
dialogs are an integral part of modern web user interfaces.&lt;/p&gt;
&lt;p&gt;Unfortunately, we didn’t have a native dialog element for a long time, leading to different
&lt;a href=&quot;https://accessuse.eu/en/modal-dialogs.html&quot;&gt;custom implementations with many accessibility issues&lt;/a&gt;.
This changed when HTML 5.2 introduced the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt;  element. With Safari finally adding
support in version 15.4, &lt;a href=&quot;https://caniuse.com/dialog&quot;&gt;all modern browsers&lt;/a&gt; now support the element.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-miguel-a-padrinan-speech-bubbles.0fhF8W61_Z1NUbqr.webp&quot; srcset=&quot;/_astro/pexels-miguel-a-padrinan-speech-bubbles.0fhF8W61_Z1FNTgA.webp 640w, /_astro/pexels-miguel-a-padrinan-speech-bubbles.0fhF8W61_jlO9b.webp 750w, /_astro/pexels-miguel-a-padrinan-speech-bubbles.0fhF8W61_1CSVna.webp 828w, /_astro/pexels-miguel-a-padrinan-speech-bubbles.0fhF8W61_Z1Y8AMY.webp 1080w, /_astro/pexels-miguel-a-padrinan-speech-bubbles.0fhF8W61_foBIH.webp 1280w, /_astro/pexels-miguel-a-padrinan-speech-bubbles.0fhF8W61_Z1NUbqr.webp 1600w&quot; alt=&quot;Two white speech bubbles on a pink background.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1064&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Miguel Á. Padriñán / pexels.com&lt;/p&gt;
&lt;p&gt;I’ll show you how easy it is to create an accessible, modal dialog using the native element. Some minor accessibility
issues remain with some browsers and screen readers, which I’ll cover at the end of the post.&lt;/p&gt;
&lt;h2 id=&quot;what-does-the-dialog-element-do&quot;&gt;What does the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt;  element do?&lt;/h2&gt;
&lt;p&gt;The dialog element creates a popup box on your website that draws the user’s attention.
The &lt;a href=&quot;https://html.spec.whatwg.org/multipage/interactive-elements.html#the-dialog-element&quot;&gt;HTML specification&lt;/a&gt; states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The dialog element represents a part of an application that a user interacts with to perform a task, for example a dialog box, inspector, or window.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A typical use case would be a modal dialog that obscures the rest of the page and asks the user for some input.
I’ve created a &lt;a href=&quot;https://alexlehner86.github.io/fancy-css-playground/#/dialog&quot;&gt;demo&lt;/a&gt; using the React framework
(&lt;a href=&quot;https://github.com/alexlehner86/fancy-css-playground/tree/main/src/pages/DialogElement&quot;&gt;source code&lt;/a&gt;):&lt;/p&gt;
&lt;iframe src=&quot;https://alexlehner86.github.io/fancy-css-playground/#/dialog&quot; title=&quot;Demo Native Dialog Element&quot;&gt;&lt;/iframe&gt;
&lt;h2 id=&quot;basic-setup-and-interaction-with-the-dialog&quot;&gt;Basic Setup and Interaction with the Dialog&lt;/h2&gt;
&lt;p&gt;The basic &lt;a href=&quot;https://reactjs.org/docs/introducing-jsx.html&quot;&gt;JSX code&lt;/a&gt; of my modal dialog demo looks like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dialog&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    aria-labelledby&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;#39;dialog-personal-info-heading&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    ref&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;formDialogRef&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    onClick&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;onFormDialogContainerClick&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;h3&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;dialog-personal-info-heading&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        Personal Information&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;h3&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;form&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        method&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;dialog&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        onClick&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; event&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;stopPropagation&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        // form elements&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dialog&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By default, the browser won’t display the dialog until you pass in an &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;open&lt;/code&gt;  property to make it
visible. It is recommended to use the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;.show()&lt;/code&gt;  or &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;.showModal()&lt;/code&gt;  methods
to render dialogs, rather than the open attribute.&lt;/p&gt;
&lt;p&gt;In my case, I want to show a modal dialog that obscures the rest of the page. In my functional React component, I retrieve
a reference to the HTML element with the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;useRef&lt;/code&gt;  hook and open the dialog on a button click:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; formDialogRef&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; useRef&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;HTMLDialogElement&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; onOpenFormDialogClick&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    formDialogRef&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;current&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;?.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;showModal&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To close the dialog, use the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;.close()&lt;/code&gt;  method. As my demo shows,
a &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;form&amp;gt;&lt;/code&gt;  element can also close the dialog using the
attribute &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;method=“dialog”&lt;/code&gt; . When the form is submitted, the dialog closes with
its &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;returnValue&lt;/code&gt;  property set to the value of the button that was used to submit the form:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; method&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;dialog&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; className&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;styles&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;formField&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; htmlFor&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;favMovie&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Favorite movie:&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;favMovie&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;text&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        type&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;submit&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        value&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;DIALOG_CONFIRM_VALUE&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        Confirm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can add an event listener for the dialog’s &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;close&lt;/code&gt;  event and trigger an action
depending on the value of the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;returnValue&lt;/code&gt;  property.&lt;/p&gt;
&lt;h2 id=&quot;styling-the-dialog-and-its-backdrop&quot;&gt;Styling the Dialog and its Backdrop&lt;/h2&gt;
&lt;p&gt;The modal dialog is rendered in the center of the page on top of the other content. Browsers apply a default style
to the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;dialog&lt;/code&gt;  element, usually a thick black border. You can easily customize the dialog’s
appearance with CSS. For example, add a drop shadow and rounded corners like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;dialog&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    border&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.125rem&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; solid&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;--border-color&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    border-radius&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;4px&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    box-shadow&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;        0&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 11px&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 15px&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; -7px&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; #0003&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;        0&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 24px&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 38px&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 3px&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; #00000024&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;        0&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 9px&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 46px&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 8px&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; #0000001f&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    font-size&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1rem&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    max-width&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;min&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;18rem&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;90vw&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A really awesome feature of the dialog element is the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;::backdrop&lt;/code&gt;  CSS pseudo-element.
It allows you to style behind a modal dialog to, e.g., dim and blur the unreachable content of the page:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;dialog::backdrop&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    background&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;rgba&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;36&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;32&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.5&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    backdrop-filter&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;blur&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.25rem&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;keyboard-and-mouse-control&quot;&gt;Keyboard and Mouse Control&lt;/h2&gt;
&lt;p&gt;When the modal dialog is opened, the browser moves focus to the first interactive element inside of the dialog.
This works well for many use cases, like my form dialog. But sometimes you would prefer to set the focus on
the whole dialog or a text element at the top. Learn more about the issue in
this &lt;a href=&quot;https://github.com/whatwg/html/wiki/dialog--initial-focus,-a-proposal&quot;&gt;proposal for initial focus placement&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While the modal dialog is active, the content obscured by the dialog is inaccessible to all users. This means
that keyboard users can’t leave the dialog with the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;TAB&lt;/code&gt;  key, and a screen reader’s virtual
cursor (arrow keys or swiping) is not allowed to leave the modal dialog as long as it remains open.&lt;/p&gt;
&lt;p&gt;Users can close the modal dialog with the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;ESC&lt;/code&gt;  key. On close, focus returns to the control that
initially activated the dialog. This allows keyboard and screen reader users to continue browsing from where they left off.&lt;/p&gt;
&lt;p&gt;Unfortunately, the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;dialog&lt;/code&gt;  element doesn’t close automatically when the user clicks outside of it.
If we want to implement this light dismiss behavior, we can get the coordinates of the click and compare them
to the dialog’s rectangle (thanks for the idea, &lt;a href=&quot;https://blog.logrocket.com/using-the-dialog-element/&quot;&gt;Amit Merchant&lt;/a&gt;):&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; isClickOutsideOfDialog&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;dialogEl&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; HTMLDialogElement&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; React&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;MouseEvent&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; boolean&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; rect&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; dialogEl&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;getBoundingClientRect&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;clientY&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; rect&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;top&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;            ||&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; event&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;clientY&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; rect&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;bottom&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;            ||&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; event&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;clientX&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; rect&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;left&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;            ||&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; event&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;clientX&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; rect&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;right&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; onFormDialogContainerClick&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; React&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;MouseEvent&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; formDialogEl&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; formDialogRef&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;current&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;formDialogEl&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;        isClickOutsideOfDialog&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;formDialogEl&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    ){&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        formDialogEl&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;close&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;DIALOG_CANCEL_VALUE&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This works fine, except for some use cases. For example, opening a native select inside the dialog would count as
a click outside of the dialog and close it. Therefore, I apply a click event listener to the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;form&lt;/code&gt; 
element and use the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;.stopPropagation()&lt;/code&gt;  method.&lt;/p&gt;
&lt;h2 id=&quot;accessibility-issues-with-some-screen-readers&quot;&gt;Accessibility Issues with some Screen Readers&lt;/h2&gt;
&lt;p&gt;The native &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;dialog&lt;/code&gt;  element works well with most screen readers and browsers. But still,
some issues remain as the accessibility audits of my &lt;a href=&quot;https://alexlehner86.github.io/fancy-css-playground/#/dialog&quot;&gt;demo&lt;/a&gt;
on different platforms have shown:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Windows 10, Google Chrome 103.0.5060.114, NVDA 2022.1&lt;/strong&gt;: When the dialog is opened and receives focus, the screen reader
announces the dialog role, the heading (thanks to &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;aria-labelledby&lt;/code&gt; ), the first paragraph and the
focused select element. Focus order and the screen reader’s virtual cursor are limited to the dialog’s content.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Windows 10, Firefox 102.0.1, NVDA 2022.1&lt;/strong&gt;: Identical to Google Chrome, except that the button that opened the dialog
is part of the focus order. Probably a Firefox bug that will be fixed in the future.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Samsung Galaxy S20, Android 12, Google Chrome 103.0.5060.71, TalkBack&lt;/strong&gt;: The screen reader only announces the focused
select element. The virtual cursor (e.g. swipe right) is limited to the dialog’s content.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Samsung Galaxy S20, Android 12, Firefox 102.2.1, TalkBack&lt;/strong&gt;: The screen reader only announces the focused
select element. The virtual cursor is not limited to the dialog’s content. This is probably due to Firefox still not
supporting the &lt;a href=&quot;https://caniuse.com/mdn-api_element_ariamodal&quot;&gt;aria-modal&lt;/a&gt; property.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;iPhone 8, iOS 15.5, Safari, VoiceOver&lt;/strong&gt;: The screen reader only announces the focused select element. The virtual cursor
can be moved outside the dialog to the elements in the header, but not to the elements in the main content section.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt;  element is easy to use and accessible by default, apart from some minor issues.
Right now, a robust custom dialog like &lt;a href=&quot;https://github.com/KittyGiraudel/a11y-dialog&quot;&gt;a11y-dialog&lt;/a&gt; might still be the
better option for some use cases. But I’m very optimistic about the native element’s future.&lt;/p&gt;
&lt;h2 id=&quot;useful-resources&quot;&gt;Useful Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog&quot;&gt;The Dialog element (MDN)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/whatwg/html/wiki/dialog--initial-focus,-a-proposal&quot;&gt;Dialog initial focus, a proposal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nngroup.com/articles/modal-nonmodal-dialog/&quot;&gt;Modal &amp;amp; Nonmodal Dialogs: When (&amp;amp; When Not) to Use Them&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 class=&quot;post-update-title&quot;&gt; &lt;span aria-hidden=&quot;true&quot;&gt;&amp;raquo;&amp;nbsp;&lt;/span&gt;Update on 03/07/2023 &lt;/h2&gt; 
&lt;p&gt;The &lt;a href=&quot;https://github.com/whatwg/html/commit/a9f103c9f7bd09ef712990194638c75db1f50e3c&quot;&gt;HTML specification has received an important update&lt;/a&gt;
regarding initial focus management. It will be possible to make the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;dialog&lt;/code&gt;  element itself
get focus if it has the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;autofocus&lt;/code&gt;  attribute set.&lt;/p&gt;
&lt;p&gt;Sure, it’ll take some time until browser vendors implement these changes. But there’s no reason to wait any longer! I agree
with &lt;a href=&quot;https://www.scottohara.me/blog/2023/01/26/use-the-dialog-element.html&quot;&gt;Scott O’Hara&lt;/a&gt;: &lt;span class=&quot;c-italic&quot;&gt;“Instead of
waiting for perfect, I personally think it’s time to move away from using custom dialogs, and to use the dialog element
instead.”&lt;/span&gt; &lt;/p&gt;
&lt;h2 class=&quot;post-update-title&quot;&gt; &lt;span aria-hidden=&quot;true&quot;&gt;&amp;raquo;&amp;nbsp;&lt;/span&gt;Update on 03/28/2026 &lt;/h2&gt; 
&lt;p&gt;Use the new &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;closedby&lt;/code&gt;  attribute instead of JavaScript to add light dismiss behavior to the dialog.
This feature should have cross-browser support until the end of the year. Learn more in my new article
&lt;a href=&quot;/blog/dialog-closedby-attribute/&quot;&gt;“Enhance Dialogs with the closedby Attribute”&lt;/a&gt;.&lt;/p&gt;</content:encoded><category>accessibility</category><category>css</category><category>demo</category><category>dialog</category><category>html</category><category>keyboard</category><category>react</category><category>sreenreader</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_speech_bubbles.jpg" length="0" type="image/jpeg"/></item><item><title>A Picture Says More Than a 1000 Words – Unless You&apos;re Blind!</title><link>https://www.oidaisdes.org/blog/how-not-to-use-images</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/how-not-to-use-images</guid><description>The basics of accessible images and common mistakes you should avoid.</description><pubDate>Sun, 03 Jul 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Visual content is awesome! Images can convey emotions, capture our imagination, or simply make a website
aesthetically more appealing. However, many people can’t visually perceive our content. Blind and visually
impaired users depend on web developers and content editors to provide alternative text.&lt;/p&gt;
&lt;p&gt;Unfortunately, a lot of websites have images with misleading alternative text or no alternative text at all.
Imagine you visit a website and instead of all the images you only see blank spaces or fuzzy images.
Not great, huh?&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-aleksandar-pasaric-nothing-to-see.BeawTXrO_Z2rAzkq.webp&quot; srcset=&quot;/_astro/pexels-aleksandar-pasaric-nothing-to-see.BeawTXrO_2cWzNy.webp 640w, /_astro/pexels-aleksandar-pasaric-nothing-to-see.BeawTXrO_10h1a9.webp 750w, /_astro/pexels-aleksandar-pasaric-nothing-to-see.BeawTXrO_Z1Nqfso.webp 828w, /_astro/pexels-aleksandar-pasaric-nothing-to-see.BeawTXrO_Z1B2Dlz.webp 1080w, /_astro/pexels-aleksandar-pasaric-nothing-to-see.BeawTXrO_1I7jBt.webp 1280w, /_astro/pexels-aleksandar-pasaric-nothing-to-see.BeawTXrO_Z2rAzkq.webp 1600w&quot; alt=&quot;A dark room with neon light letters at the back saying &apos;Nothing to see here&apos;.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1067&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Aleksandar Pasaric / pexels.com&lt;/p&gt;
&lt;p&gt;In this article, I’ll share some examples of bad alternative text that I regularly encounter in
accessibility audits. But first, let’s go over the basics.&lt;/p&gt;
&lt;h2 id=&quot;the-basics-of-accessible-images&quot;&gt;The Basics of Accessible Images&lt;/h2&gt;
&lt;p&gt;Typically, we use the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;img&lt;/code&gt;  element to display an image on our website.
With the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;alt&lt;/code&gt;  attribute we can define alternative text for the image.
The &lt;a href=&quot;https://html.spec.whatwg.org/#the-img-element&quot;&gt;HTML specification&lt;/a&gt; states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;alt — Replacement text for use when images are not available&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This means, that the alt text is displayed on the page if the image can’t be loaded, e.g because of network errors.
Of course, it’s even more important for accessibility, as screen readers read the text out to their users so they
know what the image means.&lt;/p&gt;
&lt;p&gt;Other ways to include images on a website are inline &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;svg&lt;/code&gt;  elements or the CSS pseudo
elements &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;:before&lt;/code&gt;  and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;:after&lt;/code&gt; . They pose different challenges in
regard to accessibility (see the section “Useful Resources” below).&lt;/p&gt;
&lt;h2 id=&quot;write-effective-alternative-text&quot;&gt;Write Effective Alternative Text&lt;/h2&gt;
&lt;p&gt;What all image elements have in common is the question: What kind of alternative text is appropriate for the image?
This depends on the type of image:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Informative images&lt;/strong&gt;: Images that convey relevant information. The text alternative should convey the meaning or
content that is displayed visually.
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://css-tricks.com/just-how-long-should-alt-text-be/&quot;&gt;Opinions differ&lt;/a&gt; on
whether the alt text should consist of a single, short sentence or it should describe the image in more detail with
several sentences.&lt;/li&gt;
&lt;li&gt;In case of complex images (e.g. charts and diagrams), the alternative text should be kept short and
refer to a long description that follows the image.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Decorative images&lt;/strong&gt;: Images that don’t add relevant information to the content of a page. This is the case for
images that are added to make the website more visually attractive. Or images that provide information which is
already conveyed using adjacent text. These images should be hidden from assistive technologies, e.g. by setting
an empty alternative text (&lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;alt=&amp;quot;&amp;quot;&lt;/code&gt; ).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Functional images&lt;/strong&gt;: Images used in buttons, links, and other interactive elements. In this case, the alternative
text should convey the purpose of the interactive element and not describe the image itself.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;my-personal-top-5-of-bad-alternative-text&quot;&gt;My Personal Top 5 of Bad Alternative Text&lt;/h2&gt;
&lt;p&gt;When evaluating the accessibility of websites, I regularly encounter the same alt text mistakes over and over.
So here’s my personal list of shitty alt text examples:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Title on repeat&lt;/strong&gt;: Article previews (e.g. in a news carousel) usually include a thumbnail image to illustrate the
article. A lot of times, the image’s alt text simply repeats the article’s title instead of describing the image.
This means redundant information and a waste of time for screen reader users. Please, take the time to describe what the
image actually shows!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Did the photographer take a selfie?&lt;/strong&gt; I often encounter photos with alt text that includes the copyright information.
Did the photographer take a selfie and can be seen in the picture? No? Then leave their name out of the alt text!
You can put the copyright in the visible caption of the photo.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;What does it do?&lt;/strong&gt; Another common mistake is descriptive alt text for functional images. Imagine an icon button that
visually displays a downward arrow. The button allows you to download a document. But the alt text says “arrow down”.
Not the best way to convey the button’s purpose.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;I’m not even here&lt;/strong&gt;: Take a &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;div&lt;/code&gt;  element and slap an image on it using
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;background-image&lt;/code&gt;  CSS property. &lt;span lang=&quot;fr&quot;&gt;Et voilà!&lt;/span&gt; You can see the image. But
there is no information for assistive technologies. Screen reader users won’t even notice that the image is there.
Or even worse, they’ll arrive at an image link or icon button with no information about their purpose. Thanks for nothing!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;That’s just lazy&lt;/strong&gt;: Sad, but true. I still encounter &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;img&lt;/code&gt;  tags with no
defined &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;alt&lt;/code&gt;  attribute. Just no description at all. As a fallback, screen readers announce the image’s
file name instead. Not very helpful, when the image is described as “wdkmm12xpY5.png”.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;When you include visual content on a page, take a second to answer the following questions: What is the purpose of the
image? Is it purely decorative? If not, define meaningful alternative text that describes the image or the purpose of the
link or button.&lt;/p&gt;
&lt;h2 id=&quot;useful-resources&quot;&gt;Useful Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/WAI/tutorials/images/&quot;&gt;W3C Images Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/WAI/tutorials/images/decision-tree/&quot;&gt;An alt Decision Tree&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://css-tricks.com/accessible-svgs/&quot;&gt;Accessible SVGs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://adrianroselli.com/2020/10/alternative-text-for-css-generated-content.html&quot;&gt;Alternative Text for CSS Generated Content&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>accessibility</category><category>altText</category><category>html</category><category>images</category><category>mistakes</category><category>svg</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_eye_closeup.jpg" length="0" type="image/jpeg"/></item><item><title>Creating a fancy, accessible File Input in 3 Steps</title><link>https://www.oidaisdes.org/blog/accessible-file-input</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/accessible-file-input</guid><description>Learn how to apply custom styling to the native HTML file input element.</description><pubDate>Tue, 24 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Native HTML elements are accessible by default and you can style most of them with CSS however you like – as I’ve shown in
my &lt;a href=&quot;/blog/styling-accessible-web-forms/&quot;&gt;blog post about web forms&lt;/a&gt;.
Then again, there’s elements like the file input, which is very hard to style.&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;input type=“file”&amp;gt;&lt;/code&gt;  element is rendered as a button that allows the user to open the
operating system’s file picker. This button is completely unstylable – it can’t be sized or colored, and it won’t even
accept a different font. But don’t despair! I’ll show you how to make it work.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-anete-lusina-pick-file.BQat4MZA_Z2kaLbb.webp&quot; srcset=&quot;/_astro/pexels-anete-lusina-pick-file.BQat4MZA_IM9Ih.webp 640w, /_astro/pexels-anete-lusina-pick-file.BQat4MZA_62pH7.webp 750w, /_astro/pexels-anete-lusina-pick-file.BQat4MZA_Z1Kvhgx.webp 828w, /_astro/pexels-anete-lusina-pick-file.BQat4MZA_15mxSp.webp 1080w, /_astro/pexels-anete-lusina-pick-file.BQat4MZA_ZGb2jl.webp 1280w, /_astro/pexels-anete-lusina-pick-file.BQat4MZA_Z2kaLbb.webp 1600w&quot; alt=&quot;A person is looking for a document in a briefcase.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1068&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Foto: © Anete Lusina / pexels.com&lt;/p&gt;
&lt;h2 id=&quot;step-1-use-native-html-elements&quot;&gt;Step 1: Use Native HTML Elements&lt;/h2&gt;
&lt;p&gt;When I include a file picker in a web form, I want all users to be able to select and upload files. This includes keyboard
and screen reader users as well. Which is why I’ll use the native, accessible &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;input type=“file”&amp;gt;&lt;/code&gt; 
element. I’ve created a demo using the React framework. Here’s what my &lt;a href=&quot;https://reactjs.org/docs/introducing-jsx.html&quot;&gt;JSX code&lt;/a&gt;
looks like:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; htmlFor&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;filepicker&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; className&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;styles&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;filePicker&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Upload PDF&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;input&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        id&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;filepicker&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        type&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;file&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        accept&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;.pdf&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        aria-describedby&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;selected-file&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        onChange&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; onFilePickerChange&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    /&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;selected-file&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;selectedFile&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I use a &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;label&lt;/code&gt;  element that contains the visible label of my file picker (“Upload PDF”) as well as
a visually hidden &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;input&lt;/code&gt;  element. This way, the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;label&lt;/code&gt;  element serves as the
visible UI component and you can apply any custom styling (more on that in step 2).&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;p&lt;/code&gt;  element displays the hint “No file selected” or, if a file was selected, the file’s name
(see step 3). Thanks to the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;aria-describedby&lt;/code&gt;  attribute, the text is also read by screen readers when
the user arrives at the file input.&lt;/p&gt;
&lt;p&gt;I also tried setting &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;aria-hidden=“true”&lt;/code&gt;  to hide the paragraph itself from assistive technologies. As
this led to problems with certain browser and screen reader combinations, I removed the attribute again. Now screen reader users
may hear the hint twice. Which is better than not hearing it at all.&lt;/p&gt;
&lt;h2 id=&quot;step-2-apply-css-magic&quot;&gt;Step 2: Apply CSS Magic&lt;/h2&gt;
&lt;p&gt;Next, I use CSS to visually hide the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;input&lt;/code&gt;  element and position it above the label. This
enables me to style the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;label&lt;/code&gt;  element and thereby the visible file picker however I want:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt; label&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;.filePicker&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    position&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;relative&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    background-color&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;rgb&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;49&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;92&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    color&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;white&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    font-size&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1rem&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    // ... more custom styling&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt; label&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;.filePicker&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt; input&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;file&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    position&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;absolute&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    top&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    left&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    height&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;100%&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    width&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;100%&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    opacity&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’s important that you don’t hide the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;input type=“file”&amp;gt;&lt;/code&gt;  from assistive technologies.
Using &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;display: none&lt;/code&gt;  or setting the element’s size to zero would hide it from screen readers.&lt;/p&gt;
&lt;p&gt;To give visual feedback to sighted users, I display an outline on hover and when the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;input&lt;/code&gt;  element
within the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;label&lt;/code&gt;  receives focus:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt; label&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;.filePicker:focus-within&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt; label&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;.filePicker:hover&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    outline&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;2px&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; solid&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; black&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    outline-offset&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;2px&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;step-3-a-dash-of-javascript&quot;&gt;Step 3: A Dash of JavaScript&lt;/h2&gt;
&lt;p&gt;As a last step, I want to display the file name after the user has selected a file. To achieve this, I use
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;change&lt;/code&gt;  event, which is fired when an alteration to the input’s value is committed by the user.&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; FileUpload&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; React&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;FunctionComponent&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;selectedFile&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;setSelectedFile&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; useState&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;#39;No file selected&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; onFilePickerChange&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; React&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;ChangeEvent&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;HTMLInputElement&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;&amp;gt;) &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;        const&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; files&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; Array&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;target&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;files&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; ??&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; []);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;files&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;            setSelectedFile&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;files&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;        // Only the relevant sections of the JSX code&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;file&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;            // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            onChange&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; onFilePickerChange&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        /&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;selected-file&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;selectedFile&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;        // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, you can do all that in plain JavaScript too – or any framework of your choosing. My code is simply an
example of an implementation as a React component. You can view the complete
&lt;a href=&quot;https://github.com/alexlehner86/fancy-css-playground/tree/main/src/pages/FileUpload&quot;&gt;source code on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-perfect-file-input-right&quot;&gt;The Perfect File Input, right?&lt;/h2&gt;
&lt;p&gt;Check out the result of my styled file input below. I’ve also included a standard file input for comparison:&lt;/p&gt;
&lt;iframe src=&quot;https://alexlehner86.github.io/fancy-css-playground/#/fileupload&quot; title=&quot;Demo Styled File Input&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;Awesome, right? I’m happy with the final result. But still, there’s room for improvement. The
styled &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;input type=“file”&amp;gt;&lt;/code&gt;  works perfectly for sighted keyboard users. For screen reader users,
the results are pretty good, but not perfect.&lt;/p&gt;
&lt;p&gt;Firefox fixed an &lt;a href=&quot;https://github.com/nvaccess/nvda/issues/11742&quot;&gt;important issue&lt;/a&gt; with &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;aria-describedby&lt;/code&gt; 
in version 121. At the moment of my retests, this new version was still in beta. Here’s a detailed account of my accessibility
audits on different platforms:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Windows 11, Google Chrome 120.0.6099.71, NVDA 2023.3&lt;/strong&gt;: On focus, NVDA reads “Upload pdf, button, no file selected”. After
selecting the file “testfile.pdf” the browser automatically focuses on the file input and reads “Button, upload pdf, testfile
dot pdf”. When I navigate away and then return, the screen reader announces “Upload pdf, testfile dot pdf, button, testfile
dot pdf”.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Windows 11, Firefox Beta 121.0b9, NVDA 2023.3&lt;/strong&gt;: On focus, NVDA reads “Clickable, upload pdf, browse, button, no file
selected”. After selecting the file “testfile.pdf” the browser automatically focuses on the file input and reads “Button,
upload pdf, browse, upload pdf, browse, testfile dot pdf”. When I navigate away and then return, the screen reader announces
“Clickable, upload pdf, browse, button, testfile dot pdf”.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Samsung Galaxy S20, Android 13, Google Chrome 119.0.6045.194, TalkBack&lt;/strong&gt;: On focus, TalkBack reads “Upload pdf, no file
chosen, button, no file selected, double tap to activate”. After selecting the file “testfile.pdf” the screen reader announces
the element as “Upload pdf, testfile dot pdf”.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Samsung Galaxy S20, Android 13, Firefox for Android Beta 121.0b9, TalkBack&lt;/strong&gt;: The screen reader only focuses on the text
“Upload PDF”. It provides no information about the button role or the file name. At least, the file input can be triggered via
double tap. After selecting the file “testfile.pdf”, this text is displayed next to the button and read by the screen reader on focus.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;iPhone 8, iOS 16.7.2, Safari, VoiceOver&lt;/strong&gt;: On focus, VoiceOver reads “Upload pdf, button, no file selected”.
After selecting the file “testfile.pdf” the screen reader announces the element as “Upload pdf, button, testfile pdf”.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;As my demo shows, you can create an accessible file picker with custom styling using
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;input type=“file”&amp;gt;&lt;/code&gt;  element and a bit of ingenuity.&lt;/p&gt;
&lt;p&gt;Unfortunately, I’ve encountered some accessibility problems with certain browser and screen reader combinations. Maybe this
will be fixed in future updates of the browsers and/or screen readers. Or maybe I’ll discover a better solution. We’ll see.&lt;/p&gt;
&lt;h2 class=&quot;post-update-title&quot;&gt; &lt;span aria-hidden=&quot;true&quot;&gt;&amp;raquo;&amp;nbsp;&lt;/span&gt;Update on 03/26/2023 &lt;/h2&gt; 
&lt;p&gt;I was wrong: There actually is a way to customize the native &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;input type=“file”&amp;gt;&lt;/code&gt;  HTML element.
You can use the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;::file-selector-button&lt;/code&gt;  CSS pseudo-element to style the rendered button.
Unfortunately, you can’t change the text rendered inside the button.
Here’s a &lt;a href=&quot;https://css-tricks.com/almanac/selectors/f/file-selector-button/&quot;&gt;demo with more info&lt;/a&gt; about it.&lt;/p&gt;
&lt;h2 class=&quot;post-update-title&quot;&gt; &lt;span aria-hidden=&quot;true&quot;&gt;&amp;raquo;&amp;nbsp;&lt;/span&gt;Update on 12/10/2023 &lt;/h2&gt; 
&lt;p&gt;I revised the HTML code in my example and redid the screen reader tests with the current browser versions.&lt;/p&gt;</content:encoded><category>accessibility</category><category>css</category><category>forms</category><category>html</category><category>input</category><category>javascript</category><category>screenreader</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_pick_file.jpg" length="0" type="image/jpeg"/></item><item><title>How to develop a keen sense for Digital Accessibility</title><link>https://www.oidaisdes.org/blog/develop-keen-sense-of-accessibility</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/develop-keen-sense-of-accessibility</guid><description>Approach the topic step by step and be open to new perspectives.</description><pubDate>Sun, 03 Apr 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&quot;c-italic&quot;&gt;“I would like to be able to look at a mockup for a website and immediately know: This is not
accessible!”&lt;/span&gt;  – A colleague of mine expressed this wish a few days ago. He has been working for many
years as a web developer, but still has little experience with digital accessibility.&lt;/p&gt;
&lt;p&gt;His question got me thinking: What can newbies do to develop a keen sense for accessibility?&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-eren-li-fingers-reading-braille.L9ubwvN6_Z1Bnpjg.webp&quot; srcset=&quot;/_astro/pexels-eren-li-fingers-reading-braille.L9ubwvN6_1lgeC6.webp 640w, /_astro/pexels-eren-li-fingers-reading-braille.L9ubwvN6_ZYsQQ5.webp 750w, /_astro/pexels-eren-li-fingers-reading-braille.L9ubwvN6_Z1ppmPp.webp 828w, /_astro/pexels-eren-li-fingers-reading-braille.L9ubwvN6_1inoXk.webp 1080w, /_astro/pexels-eren-li-fingers-reading-braille.L9ubwvN6_ogfKD.webp 1280w, /_astro/pexels-eren-li-fingers-reading-braille.L9ubwvN6_Z1Bnpjg.webp 1600w&quot; alt=&quot;Fingers touch the page of a book in Braille.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;904&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Eren Li / pexels.com&lt;/p&gt;
&lt;h2 id=&quot;responsive-design-whats-that-good-for&quot;&gt;Responsive Design? What’s that good for?&lt;/h2&gt;
&lt;p&gt;Younger colleagues may find it hard to imagine: But web content didn’t always fluidly adapt to different screen sizes.
Even in the 2000s it was still common to optimize websites for specific screen sizes only. The following article provides
a good summary:
&lt;a href=&quot;https://www.freecodecamp.org/news/a-brief-history-of-responsive-web-design/&quot;&gt;“A Brief History of Responsive Web Design”&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This changed when smartphones became more and more popular. Today, users expect websites to look good and work on all devices.
Responsive design is explicitly defined as a requirement for web projects. UI/UX experts create designs and prototypes for
different screen sizes. Developers test implemented features on desktop and mobile devices.&lt;/p&gt;
&lt;p&gt;Now what does that have to do with accessibility? For me, the triumph of responsive design clearly shows that the more
people use websites in a certain way, the more these needs are taken into account in web development.&lt;/p&gt;
&lt;h2 id=&quot;accessible-design-whats-that-good-for&quot;&gt;Accessible Design? What’s that good for?&lt;/h2&gt;
&lt;p&gt;Most people use their smartphone or a computer mouse to surf the Internet.
They click a button and notice the visual feedback on the page. They’re not dependent on a
&lt;a href=&quot;https://www.youtube.com/watch?v=dEbl5jvLKGQ&quot;&gt;screen reader being able to read the web content in a meaningful way&lt;/a&gt;
or on &lt;a href=&quot;https://www.youtube.com/watch?v=FvpUNiB-2T0&quot;&gt;interactive elements being accessible with the keyboard&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Web developers are users too. Their everyday experiences influence their perception of what makes a good, usable website.
For example: If you’ve never used a screen reader, it’s hard to imagine why the
&lt;a href=&quot;https://www.w3schools.com/html/html5_semantic_elements.asp&quot;&gt;semantic markup of web content is so important&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This brings me back to the central question: What can newbies do to develop a keen sense for accessibility as quickly
as possible? Very simple: &lt;strong&gt;Change perspective!&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;take-on-the-perspective-of-people-with-disabilities&quot;&gt;Take on the perspective of people with disabilities&lt;/h2&gt;
&lt;p&gt;If you want to understand the needs of people with disabilities, the best way is to just ask them how they use
digital content. Have a blind or partially sighted person show you how to shop online using a screen reader.
Talk with a deaf person about watching the news with closed captions or in sign language.&lt;/p&gt;
&lt;p&gt;If you don’t know any people with disabilities, you can organize a workshop in your company, for example.
Contact an organization of persons with disabilities in your country. Some organizations also offer specific
trainings, e.g., the
&lt;a href=&quot;https://www.myability.org/loesungen/disability-trainings/sensing-journey&quot;&gt;Sensing Journey (in German)&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;practice-makes-perfect&quot;&gt;Practice makes perfect&lt;/h2&gt;
&lt;p&gt;As a web developer, you are constantly confronted with new requirements that result from rapid technological change.
That’s why we live by the principle of “learning by doing”. This approach also helps us when it comes to digital
accessibility: Just do it!&lt;/p&gt;
&lt;p&gt;For a start, you should read up on the
&lt;a href=&quot;https://www.w3.org/WAI/WCAG21/quickref/&quot;&gt;“Web Content Accessibility Guidelines” (WCAG)&lt;/a&gt;. They’re already a legal
requirement for the public sector in all EU member states. The WCAG cover a wide range of needs from different user groups.
They provide very detailed online resources, with concrete examples of accessible implementations, as well as common mistakes.&lt;/p&gt;
&lt;p&gt;My recommendation: Most web content can be made accessible with semantic HTML and CSS alone. I often come across websites
that make excessive use of &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA&quot;&gt;ARIA attributes&lt;/a&gt;, creating more
barriers than they remove. It makes sense to use ARIA for complex UI components, as illustrated by the
&lt;a href=&quot;https://www.w3.org/TR/wai-aria-practices-1.1/&quot;&gt;WAI-ARIA Authoring Practices&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;take-your-time&quot;&gt;Take your time&lt;/h2&gt;
&lt;p&gt;Digital accessibility is complex and multi-layered. For newbies, this means a steep learning curve and a lot of potential
for frustration. You should approach the topic step by step and be open to new perspectives. Then you will develop
a keen sense for accessibility over time all by yourself.&lt;/p&gt;</content:encoded><category>accessibility</category><category>css</category><category>design</category><category>disabilities</category><category>html</category><category>ux</category><category>wcag</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_fingers_braille.jpg" length="0" type="image/jpeg"/></item><item><title>Accessible and interactive charts with Angular and Highcharts</title><link>https://www.oidaisdes.org/blog/accessible-interactive-charts</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/accessible-interactive-charts</guid><description>How to interweave Highchart&apos;s event handling with Angular&apos;s component based architecture.</description><pubDate>Sun, 13 Mar 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Column and line charts don’t have to be boring and static. Modern JavaScript libraries enable us to create
animated, interactive, and accessible charts.&lt;/p&gt;
&lt;p&gt;I’m a fan of &lt;a href=&quot;https://www.highcharts.com/&quot;&gt;Highcharts&lt;/a&gt;, a JavaScript charting library based on SVG rendering.
Several wrapper libraries exist that integrate Highcharts into the component-based architectures of React
and Angular, for example. In my demo app, I’ll show you how to interweave Highchart’s event handling with
Angular components.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-lukas-charts-on-paper.BMu0f3mY_N3ntE.webp&quot; srcset=&quot;/_astro/pexels-lukas-charts-on-paper.BMu0f3mY_Z1zCHFe.webp 640w, /_astro/pexels-lukas-charts-on-paper.BMu0f3mY_18TTtM.webp 750w, /_astro/pexels-lukas-charts-on-paper.BMu0f3mY_ZO2Rzs.webp 828w, /_astro/pexels-lukas-charts-on-paper.BMu0f3mY_Z1sl5TB.webp 1080w, /_astro/pexels-lukas-charts-on-paper.BMu0f3mY_2qymeF.webp 1280w, /_astro/pexels-lukas-charts-on-paper.BMu0f3mY_N3ntE.webp 1600w&quot; alt=&quot;A ballpen pointing at column and line charts printed on a piece of paper.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1060&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Lukas / pexels.com&lt;/p&gt;
&lt;h2 id=&quot;demo-app-selecting-a-tab-when-a-column-is-clicked&quot;&gt;Demo App: Selecting a tab when a column is clicked&lt;/h2&gt;
&lt;p&gt;I built a demo app with Angular 13, Highcharts and &lt;a href=&quot;https://www.npmjs.com/package/highcharts-angular&quot;&gt;highcharts-angular&lt;/a&gt;,
a minimal Highcharts wrapper for Angular. A column chart depicts the primary desktop screen reader usage. Several tabs
provide more information about the screen readers. When a column in the chart is clicked, the corresponding tab is selected.
Try it yourself:&lt;/p&gt;
&lt;iframe src=&quot;https://alexlehner86.github.io/highcharts-event-mgmt-in-angular/&quot; title=&quot;Demo Page Highcharts/Angular Event Management&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;So, how did I do this?&lt;/p&gt;
&lt;h3 id=&quot;step-1-define-chart-options-and-display-the-chart&quot;&gt;Step 1: Define chart options and display the chart&lt;/h3&gt;
&lt;p&gt;The Highcharts library is super convenient. You simply define your chart options and let Highcharts do the rest.
In my demo app, I define a chart with two column series:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; const&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; EXAMPLE_CHART&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; Highcharts&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;Options&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    series:&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            data:&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;                [&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;ScreenreaderName&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;Jaws&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;53.7&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;                [&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;ScreenreaderName&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;Nvda&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;30.7&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;                [&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;ScreenreaderName&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;VoiceOver&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;6.5&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;                [&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;ScreenreaderName&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;ZoomTextFusion&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;4.7&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;                [&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;ScreenreaderName&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;Other&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;4.4&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;            ],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            name:&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;#39;Worldwide&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            type:&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;#39;column&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            data:&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;                [&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;ScreenreaderName&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;Jaws&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;40.2&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;                [&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;ScreenreaderName&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;Nvda&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;41.6&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;            ],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            name:&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;#39;Europe&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            type:&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;#39;column&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    ],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    subtitle:&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        text:&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;#39;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    title:&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        text:&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;#39;Primary desktop/laptop screen reader (2021)&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    xAxis:&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        categories:&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            ScreenreaderName&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;Jaws&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            ScreenreaderName&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;Nvda&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            ScreenreaderName&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;VoiceOver&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            ScreenreaderName&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;ZoomTextFusion&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            ScreenreaderName&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;Other&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        ],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    yAxis:&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        title:&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            text:&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;#39;Usage in percent&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, in my &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;AppComponent&lt;/code&gt; , I provide the chart options and the Highcharts library:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#C586C0&quot;&gt; as&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; Highcharts&lt;/span&gt;&lt;span style=&quot;color:#C586C0&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;#39;highcharts&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;Component&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    selector:&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;#39;app-root&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    templateUrl:&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; &amp;#39;./app.component.html&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    styleUrls:&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;#39;./app.component.scss&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; AppComponent&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; chartOptions&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; EXAMPLE_CHART&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; highchartsLib&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; Highcharts&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, in the app component’s template, I pass on the library and the chart options to
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;highcharts-chart&amp;gt;&lt;/code&gt;  component:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;highcharts-chart&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    [Highcharts]&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;highchartsLib&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    [options]&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;chartOptions&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    (chartInstance)&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;addCustomPropertiesToChart($event)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;highcharts-chart&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-2-add-custom-properties-to-the-chart-instance&quot;&gt;Step 2: Add custom properties to the chart instance&lt;/h3&gt;
&lt;p&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;highcharts-chart&amp;gt;&lt;/code&gt;  component provides the output
property &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;chartInstance&lt;/code&gt; . It emits the chart instance after the chart is created.
We use this to add an arrow function as a custom property to the chart instance:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; addCustomPropertiesToChart&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;chartInstance&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;Highcharts&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;Chart&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;): &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;chartInstance&lt;/span&gt;&lt;span style=&quot;color:#C586C0&quot;&gt; as&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; MyExampleChart&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;onSeriesPointClick&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        (&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;selectScreenreaderTab&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Highchart’s &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;Chart&lt;/code&gt;  interface doesn’t define a method &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;onSeriesPointClick&lt;/code&gt; .
Therefore, we need to define our own interface that adds this custom property:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; interface&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; MyExampleChart&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; extends&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; Highcharts&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;Chart&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;    onSeriesPointClick&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; ScreenreaderName&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now our chart instance provides a method that is directly connected to the chart’s parent component.
A chart event handler can call this method to communicate, e.g., that a specific series point was clicked.&lt;/p&gt;
&lt;h3 id=&quot;step-3-call-the-custom-method-inside-an-event-handler&quot;&gt;Step 3: Call the custom method inside an event handler&lt;/h3&gt;
&lt;p&gt;In the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;plotOptions&lt;/code&gt;  property of the chart options, we define a click event handler for
&lt;a href=&quot;https://api.highcharts.com/highcharts/plotOptions.series.point.events.click&quot;&gt;all series points&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;click: &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; chart&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;series&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;chart&lt;/span&gt;&lt;span style=&quot;color:#C586C0&quot;&gt; as&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; MyExampleChart&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    chart&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;onSeriesPointClick&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#C586C0&quot;&gt; as&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; ScreenreaderName&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The event handler retrieves the chart instance that we typecast to our custom &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;MyExampleChart&lt;/code&gt; 
interface. Now we can call the custom method &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;onSeriesPointClick&lt;/code&gt;  and thereby select
the corresponding screenreader tab in our application.&lt;/p&gt;
&lt;h3 id=&quot;step-4-make-your-chart-accessible&quot;&gt;Step 4: Make your chart accessible&lt;/h3&gt;
&lt;p&gt;Highcharts provides great accessibility features. You can set colors in the chart as
&lt;a href=&quot;https://www.highcharts.com/docs/chart-design-and-style/pattern-fills&quot;&gt;pattern fills&lt;/a&gt;. This helps people with limited
color vision who benefit when information conveyed by color is available in other visual ways as well.&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;color: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    pattern: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        backgroundColor: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;#39;#96dbe7&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        color: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;#39;#080e38&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        height: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        path: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;#39;M 0 0 L 10 10 M 9 - 1 L 11 1 M - 1 9 L 1 11&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;        width: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;},&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;linkedDescription&lt;/code&gt;  property enables you to link the chart to an HTML element describing
the contents of the chart:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;accessibility: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    enabled: &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    linkedDescription: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;#39;#highcharts-description-1&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;},&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Combine Angular and Highcharts to create accessible and beautiful charts with minimal effort. With the help of custom
properties, you can even interweave Highchart’s event handling with Angular’s component-based architecture for even
more interactive experiences.&lt;/p&gt;
&lt;h2 id=&quot;resources&quot;&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://alexlehner86.github.io/highcharts-event-mgmt-in-angular/&quot;&gt;The live demo “Highcharts Event Management In Angular”&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/alexlehner86/highcharts-event-mgmt-in-angular&quot;&gt;Demo app source code on Github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/highcharts&quot;&gt;Highcharts library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/highcharts-angular&quot;&gt;Highcharts Wrapper for Angular&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>accessibility</category><category>angular</category><category>charts</category><category>demo</category><category>highcharts</category><category>javascript</category><category>typescript</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_charts_on_paper.jpg" length="0" type="image/jpeg"/></item><item><title>Create Accessible Web Forms with Custom Styling</title><link>https://www.oidaisdes.org/blog/styling-accessible-web-forms</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/styling-accessible-web-forms</guid><description>How to apply custom styling to native form controls and create accessible web forms with a consistent look across all platforms.</description><pubDate>Sat, 26 Feb 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;HTML is accessible by default. At least, if you use the right native elements. Very often, developers build
custom form controls to meet design needs – neglecting accessibility in the process.&lt;/p&gt;
&lt;p&gt;As I’ll show in this post, modern browsers enable us to apply custom styling to most native form controls.
This way, we can create accessible web forms with a consistent look across all platforms.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-steve-johnson-paint-brush.RNpWKU3z_ZSwFXj.webp&quot; srcset=&quot;/_astro/pexels-steve-johnson-paint-brush.RNpWKU3z_1QawjL.webp 640w, /_astro/pexels-steve-johnson-paint-brush.RNpWKU3z_Z2qKR0Y.webp 750w, /_astro/pexels-steve-johnson-paint-brush.RNpWKU3z_ZKbWxo.webp 828w, /_astro/pexels-steve-johnson-paint-brush.RNpWKU3z_RWi4t.webp 1080w, /_astro/pexels-steve-johnson-paint-brush.RNpWKU3z_2jhH1I.webp 1280w, /_astro/pexels-steve-johnson-paint-brush.RNpWKU3z_ZSwFXj.webp 1600w&quot; alt=&quot;Brush and spatula on a brightly painted canvas.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1067&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Steve Johnson / pexels.com&lt;/p&gt;
&lt;h2 id=&quot;when-design-needs-wreck-accessibility&quot;&gt;When Design Needs wreck Accessibility&lt;/h2&gt;
&lt;p&gt;Native form controls like &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;input&lt;/code&gt;  or &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;select&lt;/code&gt;  are accessible
by default. They receive focus when keyboard users press the tab key. The enter and space key can be used
to interact with them, e.g., to mark a checkbox as checked. They communicate their role and current state
to screen readers.&lt;/p&gt;
&lt;p&gt;Sounds great! You would be mad not to use native form controls and, instead, build custom UI components
with non-semantic spaghetti code. Right? Well, the sad truth is: Using custom form controls is a common practice.
And most of the time they’re not accessible. Let’s look at an example for a custom select:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;custom-select&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;select-trigger&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;PlayStation 5&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;arrow&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;custom-options&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;option selected&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;            PlayStation 5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;option&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Nintendo Switch&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;option&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Xbox Series X&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By itself, this mess of &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;div&lt;/code&gt;  and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;span&lt;/code&gt;  tags is not accessible
to keyboard and screen reader users. Yes, you can fix this with ARIA attributes and keydown event listeners.
But many developers are either not aware of this or simply don’t care. What they care about is styling
the custom elements to meet the design needs of their clients.&lt;/p&gt;
&lt;h2 id=&quot;why-styling-native-form-controls-can-be-challenging&quot;&gt;Why Styling Native Form Controls can be challenging&lt;/h2&gt;
&lt;p&gt;Using CSS to style form controls has historically been difficult. Browsers apply their own default styling and
form controls vary greatly in how easy they are to customize with CSS. Fortunately, this is getting easier as
old browsers are retired (bye-bye IE11) and modern browsers offer more features to use.&lt;/p&gt;
&lt;p&gt;Mozilla has a great article on &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn/Forms/Styling_web_forms&quot;&gt;styling web forms&lt;/a&gt;,
which I highly recommend. They categorize native form controls into three groups: “The good”, “The bad”, and
“The ugly”. I mostly agree with them, except for considering checkboxes and radio buttons difficult to style.
This may have been true in the past, but modern CSS allows you to do whatever you want as I’ll show you.&lt;/p&gt;
&lt;h2 id=&quot;styling-example-1-radio-buttons&quot;&gt;Styling Example 1: Radio Buttons&lt;/h2&gt;
&lt;p&gt;In order to style your radio buttons with CSS, you need to set the value of the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;appearance&lt;/code&gt; 
property to &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;none&lt;/code&gt; . This removes the default appearance applied by the browser and operating
system. Now you can get creative and even apply smooth CSS transitions if you like:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;radio&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    -webkit-appearance&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;none&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    appearance&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;none&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    box-sizing&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;border-box&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    position&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;relative&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    width&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1.4em&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    height&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1.4em&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    border&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.15rem&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; solid&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; darkred&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    border-radius&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;50%&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;radio&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;::before&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    position&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;absolute&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    top&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;50%&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    left&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;50%&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    content&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    width&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.7em&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    height&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.7em&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    border-radius&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;50%&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    background-color&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;darkred&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;    /* scale(0) hides the dot in unchecked state */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transform&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;translate&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;-50%&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;-50%&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;scale&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transform-origin&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;center&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transition&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;all&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 0.3s&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; ease-in&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;radio&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;:checked::before&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transform&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;translate&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;-50%&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;-50%&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;scale&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    transition&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;all&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt; 0.3s&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; cubic-bezier&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.25&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.25&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.56&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In my example, I defined the unchecked state of the radio button to appear as a darkred circle.
With the help of the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;::before&lt;/code&gt;  pseudo-element and the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;:checked&lt;/code&gt; 
pseudo-class, a darkred dot appears inside the circle when the radio button is selected. Check out the
&lt;a href=&quot;https://codepen.io/alexlehner86/pen/mdqGLxZ&quot;&gt;demo on CodePen&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;styling-example-2-select&quot;&gt;Styling Example 2: Select&lt;/h2&gt;
&lt;p&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;select&lt;/code&gt;  element belongs to the category “The ugly”. The problem with the
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn/Forms/Advanced_form_styling#what_can_be_done_about_the_ugly_elements&quot;&gt;form controls in this group&lt;/a&gt;
is that they have very different default looks across browsers. You can style them to some degree with CSS,
but some parts of their internals are literally impossible to style.&lt;/p&gt;
&lt;p&gt;You can use the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;appearance&lt;/code&gt;  property to override the default look of
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;select&lt;/code&gt;  element. But this will not affect the list of options that appears
when you click on the element. Styling the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;option&lt;/code&gt;  element with CSS is highly
limited and only supported by some browsers.&lt;/p&gt;
&lt;p&gt;In my opinion, the styling options are sufficient to meet basic design needs (e.g. color and font). Take a look at
my &lt;a href=&quot;https://codepen.io/alexlehner86/pen/mdqGLxZ&quot;&gt;demo on CodePen&lt;/a&gt; where I used the following styling:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;select&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    -webkit-appearance&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;none&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    appearance&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;none&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    box-sizing&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;border-box&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    background-color&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;white&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    background-image&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;        url&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;#39;/assets/custom_arrow_for_select.svg&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    background-position&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;right&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    background-repeat&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;no-repeat&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    background-size&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;contain&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    border&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.25rem&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; solid&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; darkred&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    padding&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;0.25em&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;    /* Leave enough space for the arrow on the right */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    padding-right&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;2em&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;native-html-is-always-better&quot;&gt;Native HTML is always better&lt;/h2&gt;
&lt;p&gt;What I wanted to show with this post is: Using native HTML is always better than messing around
with custom UI components. Because keyboard and screen reader accessibility is already built in.
Therefore, I would always pick the native form control if it can be sufficiently styled with CSS.&lt;/p&gt;</content:encoded><category>accessibility</category><category>css</category><category>design</category><category>forms</category><category>html</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_paint_brush.jpg" length="0" type="image/jpeg"/></item><item><title>Spell it out! Determine how Screen Readers should read text</title><link>https://www.oidaisdes.org/blog/spell-it-out-screen-reader</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/spell-it-out-screen-reader</guid><description>Use the speak-as CSS property to tell screen readers how to read numbers and abbreviations.</description><pubDate>Sun, 13 Feb 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Numbers, abbreviations and equations can pose a challenge for screen reader users. Using
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;speak-as&lt;/code&gt;  CSS property, you can determine how text should be read.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-edmond-dantes-megaphone.DFdg2kJG_1wVGnY.webp&quot; srcset=&quot;/_astro/pexels-edmond-dantes-megaphone.DFdg2kJG_Z2p6vgj.webp 640w, /_astro/pexels-edmond-dantes-megaphone.DFdg2kJG_Z5JGJK.webp 750w, /_astro/pexels-edmond-dantes-megaphone.DFdg2kJG_Z5mTMC.webp 828w, /_astro/pexels-edmond-dantes-megaphone.DFdg2kJG_Z1jTfWC.webp 1080w, /_astro/pexels-edmond-dantes-megaphone.DFdg2kJG_ZgEpoJ.webp 1280w, /_astro/pexels-edmond-dantes-megaphone.DFdg2kJG_1wVGnY.webp 1600w&quot; alt=&quot;Woman Speaking into a Megaphone.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1067&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Edmond Dantès / pexels.com*&lt;/p&gt;
&lt;h2 id=&quot;to-spell-or-not-to-spell-that-is-the-question&quot;&gt;To spell, or not to spell, that is the question&lt;/h2&gt;
&lt;p&gt;Some days ago, I consulted a client in the banking industry. They want to optimize their web application for
screen reader users. One of their questions was: How can we make the screen reader read numbers one at a time?
For example, a bank account number with 12 digits or more?&lt;/p&gt;
&lt;p&gt;In many cases, screen readers will announce the whole number instead of the single digits. For example, 9100 will
be read as “nine thousand one hundred” instead of “nine one zero zero”. Similar problems can arise with abbreviations
or equations. It all comes down to the
&lt;a href=&quot;https://www.deque.com/blog/dont-screen-readers-read-whats-screen-part-1-punctuation-typographic-symbols/&quot;&gt;screen reader’s inherent heuristics&lt;/a&gt;
that determine how to read specific letters and punctuation.&lt;/p&gt;
&lt;p&gt;Well, wouldn’t it be great if we could just tell the screen reader how to read certain content? The answer is:
Yes, we can! But browser support is really bad.&lt;/p&gt;
&lt;h2 id=&quot;the-css-speak-as-property&quot;&gt;The CSS speak-as property&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.w3.org/TR/css-speech-1/&quot;&gt;CSS Speech Module&lt;/a&gt; defines the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;speak-as&lt;/code&gt;  property.
It determines in what manner text gets rendered aurally, based upon a predefined list of possibilities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;normal&lt;/strong&gt;: Uses the browser’s language-dependent pronunciation rules (default).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;spell-out&lt;/strong&gt;: Instructs the browser to spell the text one letter at a time (useful for acronyms and abbreviations).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;digits&lt;/strong&gt;: Speak numbers one digit at a time, like 9100 would be read “nine one zero zero”.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;literal-punctuation&lt;/strong&gt;: Spells out punctations (like semicolons, braces, etc.) rather than treating them like pauses.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;no-punctuation&lt;/strong&gt;: Entirely skips punctuation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Using this property, we could define a class for bank account numbers like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;.bank-account-number&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    speak-as&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;digits&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;browser-and-screen-reader-support&quot;&gt;Browser and Screen Reader Support&lt;/h2&gt;
&lt;p&gt;This all sounds great in theory. Unfortunately, it won’t work with most browsers and screen readers. I put together a
&lt;a href=&quot;https://codepen.io/alexlehner86/pen/OJOMmzm&quot;&gt;demo on CodePen&lt;/a&gt; and tested the following scenarios:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;NVDA 2021.3.1, Google Chrome 98.0.4758.82, Windows 10&lt;/li&gt;
&lt;li&gt;TalkBack, Firefox 97.1.0, Android 12&lt;/li&gt;
&lt;li&gt;VoiceOver, Safari 15, iOS 15.1&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Out of the three, only VoiceOver does a great job and reads the content according to the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;speak-as&lt;/code&gt; 
property’s value. NVDA and TalkBack completely ignore it.&lt;/p&gt;
&lt;p&gt;Considering the fact that the CSS Speech Module was written over 10 years ago, I’m very disappointed by the current
situation. I hope that more browsers and screen readers will support the feature in the future!&lt;/p&gt;</content:encoded><category>accessibility</category><category>css</category><category>screenreader</category><category>speech</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_megaphone.jpg" length="0" type="image/jpeg"/></item><item><title>3 Underrated HTML elements that are actually awesome</title><link>https://www.oidaisdes.org/blog/3-underrated-awesome-html-elements</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/3-underrated-awesome-html-elements</guid><description>Use the time, picture and dl elements for machine-readable dates, faster loading images and better accessibility.</description><pubDate>Sat, 05 Feb 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Did you know that there are over 100 different HTML elements? We’re all familiar with common elements
like &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; , &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;p&amp;gt;&lt;/code&gt;  or &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;img&amp;gt;&lt;/code&gt; .
But many elements lead a niche existence. Some web developers don’t even know they exist.&lt;/p&gt;
&lt;p&gt;That’s why in this article I’d like to bring three underrated HTML elements to the
fore: &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;time&amp;gt;&lt;/code&gt; , &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;picture&amp;gt;&lt;/code&gt;  and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;dl&amp;gt;&lt;/code&gt; .&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-olya-kobruseva-calendar.BYzGUoEm_Z1AJz6Q.webp&quot; srcset=&quot;/_astro/pexels-olya-kobruseva-calendar.BYzGUoEm_1bjtLN.webp 640w, /_astro/pexels-olya-kobruseva-calendar.BYzGUoEm_ZbUT5q.webp 750w, /_astro/pexels-olya-kobruseva-calendar.BYzGUoEm_Zby78i.webp 828w, /_astro/pexels-olya-kobruseva-calendar.BYzGUoEm_BABlt.webp 1080w, /_astro/pexels-olya-kobruseva-calendar.BYzGUoEm_ZCOyOJ.webp 1280w, /_astro/pexels-olya-kobruseva-calendar.BYzGUoEm_Z1AJz6Q.webp 1600w&quot; alt=&quot;A desk calendar showing the month of January. There&apos;s a pair of glasses on the calendar.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1068&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Olya Kobruseva / pexels.com&lt;/p&gt;
&lt;h2 id=&quot;the-time-element-machine-readable-dates&quot;&gt;The time element: Machine-readable dates&lt;/h2&gt;
&lt;p&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;time&amp;gt;&lt;/code&gt;  &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/time&quot;&gt;HTML element&lt;/a&gt;
represents a specific point in time, date, or period. Together with the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;datetime&lt;/code&gt;  attribute,
the date is provided in a machine-readable format. What’s that good for? Here’s an example:&lt;/p&gt;
&lt;iframe title=&quot;Code example for the time element&quot; src=&quot;https://codepen.io/alexlehner86/embed/PoOGRwZ?default-tab=result&quot; loading=&quot;lazy&quot; allowtransparency=&quot;true&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/alexlehner86/pen/PoOGRwZ&quot;&gt;
time element German&lt;/a&gt; by Alexander Lehner (&lt;a href=&quot;https://codepen.io/alexlehner86&quot;&gt;@alexlehner86&lt;/a&gt;)
on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;&lt;/iframe&gt;
&lt;p&gt;The example above shows three events, each with a date displayed in a tear-off calendar style. Maybe your thinking:
Dude, that’s self-explanatory! Together with the heading “Events 2022” it’s clear what the precise dates are.&lt;/p&gt;
&lt;p&gt;Sighted people will probably have no problem with this representation of the date. But that’s not true for blind or
visually impaired users. When the screen reader announces “mar four” or “jul eight”, it will be confusing.
Use the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;time&amp;gt;&lt;/code&gt;  element to provide clarity.&lt;/p&gt;
&lt;p&gt;Unfortunately, not all popular screen readers support the element. &lt;a href=&quot;https://en.wikipedia.org/wiki/VoiceOver&quot;&gt;VoiceOver&lt;/a&gt;
correctly reads out the date defined in the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;datetime&lt;/code&gt;  attribute (tested with iPhone 8, iOS 15,
Safari). Sadly, it doesn’t work with NVDA and TalkBack at the moment.&lt;/p&gt;
&lt;h2 id=&quot;the-picture-element-load-images-based-on-screen-size&quot;&gt;The picture element: Load images based on screen size&lt;/h2&gt;
&lt;p&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;picture&amp;gt;&lt;/code&gt;  &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture&quot;&gt;HTML element&lt;/a&gt;
is an image container that enables you to offer alternative versions of an image for different display/device scenarios.
It contains one &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;img&amp;gt;&lt;/code&gt;  element and usually several &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;source&amp;gt;&lt;/code&gt;  elements.
Consider the following example:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;picture&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;source&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; srcset&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;cat_lg.avif&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;image/avif&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; media&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;(min-width: 60rem)&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;source&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; srcset&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;cat_md.avif&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;image/avif&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;source&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; srcset&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;cat_lg.webp&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;image/webp&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; media&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;(min-width: 60rem)&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;source&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; srcset&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;cat_md.webp&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;image/webp&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;source&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; srcset&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;cat_lg.jpg&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; media&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;(min-width: 60rem)&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;img&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; src&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;cat_md.jpg&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; alt&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;An adorable cat&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; loading&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;lazy&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; decoding&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;async&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;picture&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;type&lt;/code&gt;  attribute specifies a MIME type for the resource defined in the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;srcset&lt;/code&gt; 
attribute. In the example above, the first &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;source&amp;gt;&lt;/code&gt;  element points to an image in the modern
&lt;a href=&quot;https://en.wikipedia.org/wiki/AVIF&quot;&gt;AVIF format&lt;/a&gt;. The browser will pick this image if it’s capable of rendering AVIF images.
Otherwise, it moves on to the next &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;source&amp;gt;&lt;/code&gt;  element.&lt;/p&gt;
&lt;p&gt;This allows modern browsers that support AVIF or &lt;a href=&quot;https://en.wikipedia.org/wiki/WebP&quot;&gt;WebP format&lt;/a&gt; to load a highly compressed,
high-quality image. Older browsers can access the JPG version of the image instead.&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;media&lt;/code&gt;  attribute specifies a media query that the browser will evaluate. In the example we’re
telling the browser that if the viewport width is wider than 60 rem it must use the large image. If the media query
evaluates to false, the browser skips it and evaluates the next &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;source&amp;gt;&lt;/code&gt;  element.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-ihsan-adityawarman-sleeping-cat.FMWrRJKL_Z5SlGI.webp&quot; srcset=&quot;/_astro/pexels-ihsan-adityawarman-sleeping-cat.FMWrRJKL_1K1oh9.webp 640w, /_astro/pexels-ihsan-adityawarman-sleeping-cat.FMWrRJKL_ZGSWE4.webp 750w, /_astro/pexels-ihsan-adityawarman-sleeping-cat.FMWrRJKL_Z1f3Elr.webp 828w, /_astro/pexels-ihsan-adityawarman-sleeping-cat.FMWrRJKL_ZUcyqj.webp 1080w, /_astro/pexels-ihsan-adityawarman-sleeping-cat.FMWrRJKL_1fgekr.webp 1280w, /_astro/pexels-ihsan-adityawarman-sleeping-cat.FMWrRJKL_Z5SlGI.webp 1600w&quot; alt=&quot;A sleeping cat with black-grey fur.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1067&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Ihsan Adityawarman / pexels.com&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;srcset&lt;/code&gt;  attribute offers another option for image optimization. You can also use it together
with an &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;img&amp;gt;&lt;/code&gt;  element, as shown in the cute cat picture above. Its HTML code looks something like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;img&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    srcset&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;cat-480w.jpg 480w, cat-800w.jpg 800w&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    sizes&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;(max-width: 600px) 480px, 800px&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    src&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;cat-800w.jpg&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    alt&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&amp;quot;A sleeping cat with black-grey fur.&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;srcset&lt;/code&gt;  attribute defines a set of images we will allow the browser to choose between,
and what size each image is. The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;sizes&lt;/code&gt;  attribute defines a set of conditions (e.g. screen widths)
and indicates what image size would be best to choose, when certain media queries evaluate to true.&lt;/p&gt;
&lt;p&gt;If you want to delve deeper into the topic, I can recommend the following articles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images&quot;&gt;Responsive Images (MDN Web Docs)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/learn/design/picture-element/&quot;&gt;The picture element (web.dev)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;markup-key-value-pairs-with-dl-dt-and-dd&quot;&gt;Markup key-value pairs with dl, dt and dd&lt;/h2&gt;
&lt;p&gt;Lists are one of the basic building blocks of HTML. Every web developer knows the HTML
elements &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;ul&amp;gt;&lt;/code&gt;  and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;ol&amp;gt;&lt;/code&gt;  for
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul&quot;&gt;unordered&lt;/a&gt;
and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ol&quot;&gt;ordered lists&lt;/a&gt;.
Yet few are familiar with their close relative &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;dl&amp;gt;&lt;/code&gt; .&lt;/p&gt;
&lt;p&gt;The so called &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dl&quot;&gt;description list&lt;/a&gt; contains a list
of terms and descriptions that are defined with the HTML elements &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;dt&amp;gt;&lt;/code&gt; 
and &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;dd&amp;gt;&lt;/code&gt; . Common uses are to display a glossary or metadata (a list of key-value pairs).&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dl&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dt&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Account Owner&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dt&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dd&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Martina Musterfrau&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dd&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dt&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Banking Institute&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dt&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dd&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;Musterbank&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dd&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dt&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;IBAN&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dt&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dd&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;AT12 3456 7891 2345 6789&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dd&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;dl&lt;/span&gt;&lt;span style=&quot;color:#808080&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Why do I think this element is awesome? You guessed it! It conveys the content in a programmatic way that screen
readers can understand. But web developers also benefit from it. Think of the example above as a sequence
of &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;&amp;lt;div&amp;gt;&lt;/code&gt;  elements. Which code block is more readable and easier to navigate?
&lt;strong&gt;Semantic HTML makes code more readable!&lt;/strong&gt;&lt;/p&gt;</content:encoded><category>html</category><category>images</category><category>seo</category><category>time</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_calendar.jpg" length="0" type="image/jpeg"/></item><item><title>Lights Off! Experience how Blind Users navigate the Web</title><link>https://www.oidaisdes.org/blog/lights-off-how-blind-users-navigate</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/lights-off-how-blind-users-navigate</guid><description>What does it feel like to be blind? Turn everything black and experience the web as a blind user would.</description><pubDate>Sat, 29 Jan 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;What does it feel like to be blind? How can you navigate a website and read the content? My demo page
“Come to the Dark Side” allows you to turn everything black and experience the website as a blind user would.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-victor-freitas-eye-closeup.BhU32UfC_1tDegJ.webp&quot; srcset=&quot;/_astro/pexels-victor-freitas-eye-closeup.BhU32UfC_18jEX7.webp 640w, /_astro/pexels-victor-freitas-eye-closeup.BhU32UfC_Z1Mt1PQ.webp 750w, /_astro/pexels-victor-freitas-eye-closeup.BhU32UfC_1fzJKh.webp 828w, /_astro/pexels-victor-freitas-eye-closeup.BhU32UfC_Z1mTWNq.webp 1080w, /_astro/pexels-victor-freitas-eye-closeup.BhU32UfC_ijbwB.webp 1280w, /_astro/pexels-victor-freitas-eye-closeup.BhU32UfC_1tDegJ.webp 1600w&quot; alt=&quot;Closeup of a person&apos;s eye.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1067&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Victor Freitas / pexels.com&lt;/p&gt;
&lt;h2 id=&quot;22-billion-people-have-a-vision-impairment&quot;&gt;2.2 billion people have a vision impairment&lt;/h2&gt;
&lt;p&gt;According to the &lt;a href=&quot;https://www.who.int/publications/i/item/9789241516570&quot;&gt;“World report on vision 2019”&lt;/a&gt;,
about 2.2 billion people around the world are blind or visually impaired. Many of them use a screen reader to
navigate the web.&lt;/p&gt;
&lt;p&gt;As a person that can see, it can be hard to truly understand what that means: No visual input, relying
only on the auditory feedback a screen reader provides.&lt;/p&gt;
&lt;p&gt;Because I’m a curious person, I put together a demo page that allows you to experience what it feels like
to be a blind web user. My goal is to help people get a better understanding of how important accessible web
content is for blind users.&lt;/p&gt;
&lt;h2 id=&quot;come-to-the-dark-side&quot;&gt;Come to the Dark Side&lt;/h2&gt;
&lt;p&gt;I’ve included my &lt;a href=&quot;https://alexlehner86.github.io/come-to-the-dark-side/&quot;&gt;demo page&lt;/a&gt; below.
Simply activate your screen reader and turn everything black via the “Go Dark” button in the header.&lt;/p&gt;
&lt;iframe src=&quot;https://alexlehner86.github.io/come-to-the-dark-side/&quot; title=&quot;Demo Page Come to the Dark Side&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;I look forward to your feedback! Just hit me up on &lt;a href=&quot;https://tech.lgbt/@alex86&quot;&gt;Mastodon&lt;/a&gt;.&lt;/p&gt;</content:encoded><category>accessibility</category><category>blind</category><category>demo</category><category>screenreader</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_eye_closeup.jpg" length="0" type="image/jpeg"/></item><item><title>Provide highly visible Keyboard Focus with :focus-visible</title><link>https://www.oidaisdes.org/blog/highly-visible-keyboard-focus</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/highly-visible-keyboard-focus</guid><description>Fancy design or accessibility? The :focus-visible pseudo-class enables you to support keyboard-only users and satisfy clients.</description><pubDate>Sat, 22 Jan 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Fancy design or accessibility? The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;:focus-visible&lt;/code&gt;  pseudo-class enables you
to support keyboard-only users and, at the same time, satisfy the aesthetic expectations of your clients.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-cottonbro-keyboard.S0lQaG98_ZWJYFF.webp&quot; srcset=&quot;/_astro/pexels-cottonbro-keyboard.S0lQaG98_ZWudMY.webp 640w, /_astro/pexels-cottonbro-keyboard.S0lQaG98_HnbJ1.webp 750w, /_astro/pexels-cottonbro-keyboard.S0lQaG98_ZlgvEo.webp 828w, /_astro/pexels-cottonbro-keyboard.S0lQaG98_Z27NIX3.webp 1080w, /_astro/pexels-cottonbro-keyboard.S0lQaG98_5c0oj.webp 1280w, /_astro/pexels-cottonbro-keyboard.S0lQaG98_ZWJYFF.webp 1600w&quot; alt=&quot;Closeup of a person&apos;s hands typing on a laptop keyboard.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1067&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © cottonbro / pexels.com&lt;/p&gt;
&lt;h2 id=&quot;the-importance-of-keyboard-focus&quot;&gt;The Importance of Keyboard Focus&lt;/h2&gt;
&lt;p&gt;Being able to navigate with a keyboard is an important feature of accessible websites. This benefits
people with motor impairments who rely on a keyboard, instead of a mouse, to navigate a web page.
Providing a &lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/focus-visible.html&quot;&gt;visual indicator&lt;/a&gt; that
clearly highlights the element that currently has keyboard focus is therefore indispensable.&lt;/p&gt;
&lt;p&gt;Browsers provide a &lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Techniques/general/G149&quot;&gt;default focus indicator&lt;/a&gt; to
ensure that keyboard focus is visible. In CSS, the styling of the focus indicator can be changed via
the &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;:focus&lt;/code&gt;  pseudo-class. For example:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;button:focus&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    outline&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;2px&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; solid&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; purple&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;design-versus-accessibility&quot;&gt;Design versus Accessibility&lt;/h2&gt;
&lt;p&gt;I think we can all agree that a visual focus indicator is very helpful for keyboard users. On the other hand,
the focus indicator also appears when users click an element with a mouse or touch it with their finger.
For some users, this can be distracting or even irritating. Especially, without the knowledge that highlighting
the element is actually an accessibility feature.&lt;/p&gt;
&lt;p&gt;Often, web developers have to deal with clients and designers, who insist that they remove the focus styles
altogether for purely aesthetic reasons. Consequently, many websites define CSS rules like this one:&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;button:focus&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    outline&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;none&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Please, don’t do this! You would actively exclude people who depend on keyboard navigation.&lt;/p&gt;
&lt;h2 id=&quot;the-solution-is-focus-visible&quot;&gt;The Solution is :focus-visible&lt;/h2&gt;
&lt;p&gt;There is a way to reconcile accessibility with design expectations: The &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;:focus-visible&lt;/code&gt; 
pseudo-class. The &lt;a href=&quot;https://www.w3.org/TR/selectors-4/#the-focus-visible-pseudo&quot;&gt;specification&lt;/a&gt; states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The :focus-visible pseudo-class applies while an element matches the :focus pseudo-class and
the user agent determines via heuristics that the focus should be made evident on the element.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This means: It lets you show focus styles only when they are needed, that is to say, when an element receives
focus and the browser determines that the focus indicator should be shown (e.g., on keyboard navigation).&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;/* Hide focus styles if they&amp;#39;re not needed. */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;button:focus:not&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;:focus-visible&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    outline&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;none&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;/* Show focus styles on keyboard focus. */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;button:focus-visible&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    outline&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;2px&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; solid&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; purple&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This way, you gain precise control over when the focus indicator of e.g., buttons and links is shown.
For some elements like input fields, the focus indicator will still be shown when the users click on it.
This is because clicking the input field activates keyboard input. You can test this behavior
in my &lt;a href=&quot;https://alexlehner86.github.io/fancy-css-playground/#/a11yfeatures&quot;&gt;demo&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;browser-support&quot;&gt;Browser Support&lt;/h2&gt;
&lt;p&gt;Most modern browsers already &lt;a href=&quot;https://caniuse.com/css-focus-visible&quot;&gt;support the feature&lt;/a&gt;.
Safari also added support for &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;:focus-visible&lt;/code&gt;  with
&lt;a href=&quot;https://developer.apple.com/documentation/safari-release-notes/safari-15_4-release-notes&quot;&gt;version 15.4&lt;/a&gt;.
Still, I’d recommend you define regular focus styles for non-supporting browsers and then overwrite them
for browsers that support &lt;code class=&quot;c-code&quot; lang=&quot;en&quot;&gt;:focus-visible&lt;/code&gt; .&lt;/p&gt;
&lt;pre class=&quot;astro-code slack-dark&quot; style=&quot;background-color:#222222;color:#E6E6E6;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;/* Regular focus styles for non-supporting browsers. */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;button:focus&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    outline&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;2px&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; solid&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; purple&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;/* For browsers that support :focus-visible */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;@supports&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; (:focus-visible) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;    button:focus:not&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;:focus-visible&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        outline&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;none&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D7BA7D&quot;&gt;    button:focus-visible&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;        outline&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;2px&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; solid&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; purple&lt;/span&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6E6E6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;useful-links&quot;&gt;Useful Links&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.deque.com/blog/accessible-focus-indicators/&quot;&gt;Accessible Focus Indicators: Something to :focus on&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/focus-visible.html&quot;&gt;WCAG 2.1 Success Criterion 2.4.7: Focus Visible&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/focus-appearance-minimum.html&quot;&gt;WCAG 2.2 Success Criterion 2.4.11: Focus Appearance (Minimum)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible&quot;&gt;MDN page about :focus-visible&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 class=&quot;post-update-title&quot;&gt; &lt;span aria-hidden=&quot;true&quot;&gt;&amp;raquo;&amp;nbsp;&lt;/span&gt;Update on 04/14/2022 &lt;/h2&gt; 
&lt;p&gt;Post updated for Safari 15.4.&lt;/p&gt;</content:encoded><category>accessibility</category><category>css</category><category>design</category><category>focusIndicator</category><category>keyboard</category><category>wcag</category><category>web</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_keyboard.jpg" length="0" type="image/jpeg"/></item><item><title>5 Tips for getting started with Accessibility Audits using a screen reader</title><link>https://www.oidaisdes.org/blog/a11y-audits-screenreader</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/a11y-audits-screenreader</guid><description>How to efficiently use a screen reader and which keyboard shortcuts and gestures will make your life easier.</description><pubDate>Sat, 15 Jan 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The hardest part is getting started: How to efficiently use a screen reader
and which keyboard shortcuts and gestures will make your life easier.&lt;/p&gt;
&lt;img src=&quot;/_astro/pexels-kampus-finger-tap-smartphone.B_6wqSgx_2KOwy.webp&quot; srcset=&quot;/_astro/pexels-kampus-finger-tap-smartphone.B_6wqSgx_2cBSYI.webp 640w, /_astro/pexels-kampus-finger-tap-smartphone.B_6wqSgx_Z2u04mc.webp 750w, /_astro/pexels-kampus-finger-tap-smartphone.B_6wqSgx_wFhz6.webp 828w, /_astro/pexels-kampus-finger-tap-smartphone.B_6wqSgx_1jOAML.webp 1080w, /_astro/pexels-kampus-finger-tap-smartphone.B_6wqSgx_2jFsiu.webp 1280w, /_astro/pexels-kampus-finger-tap-smartphone.B_6wqSgx_2KOwy.webp 1600w&quot; alt=&quot;A woman touches the screen of a smartphone with her index finger.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;1068&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Kampus Production / pexels.com&lt;/p&gt;
&lt;h2 id=&quot;my-first-time&quot;&gt;My First Time&lt;/h2&gt;
&lt;p&gt;Three years ago, when I activated a screen reader on my laptop for the first time, I briefly panicked.
A robotic voice began talking to me at high speed. Intuitively I tried to match what I heard
to what I saw on the screen – and failed miserably. Very stressful!&lt;/p&gt;
&lt;p&gt;Using a screen reader can be confusing at first, especially for sighted people. For example, for
web developers who want to check a newly implemented feature for accessibility. Or for testers
who want to audit an application for the blind and visually impaired.
So I want to share a few tips to make it easier to get started.&lt;/p&gt;
&lt;img src=&quot;/_astro/iphone-voiceover-settings.5UW1NgW4_Z2wo1HG.webp&quot; srcset=&quot;/_astro/iphone-voiceover-settings.5UW1NgW4_Z2rCtdq.webp 640w, /_astro/iphone-voiceover-settings.5UW1NgW4_Z1GsGAN.webp 750w, /_astro/iphone-voiceover-settings.5UW1NgW4_17J7F1.webp 828w, /_astro/iphone-voiceover-settings.5UW1NgW4_ZSGDpN.webp 1080w, /_astro/iphone-voiceover-settings.5UW1NgW4_1SvSyK.webp 1280w, /_astro/iphone-voiceover-settings.5UW1NgW4_Z2wo1HG.webp 1600w&quot; alt=&quot;Settings menu on the iPhone for the screen reader VoiceOver.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; sizes=&quot;(min-width: 1600px) 1600px, 100vw&quot; style=&quot;--fit: cover; --pos: center;&quot; data-astro-image=&quot;constrained&quot; width=&quot;1600&quot; height=&quot;900&quot;&gt;
&lt;p class=&quot;copyright&quot;&gt;Photo: © Alexander Lehner&lt;/p&gt;
&lt;h2 id=&quot;tips-for-beginners&quot;&gt;Tips for Beginners&lt;/h2&gt;
&lt;p&gt;For desktop devices running Windows, I can recommend the free screen reader &lt;a href=&quot;https://www.nvaccess.org/&quot;&gt;NVDA&lt;/a&gt;.
The screen reader &lt;a href=&quot;https://en.wikipedia.org/wiki/VoiceOver&quot;&gt;VoiceOver&lt;/a&gt; is already pre-installed on Apple devices like the
iPhone. The counterpart on Android devices is called &lt;a href=&quot;https://support.google.com/accessibility/android/answer/6283677?hl=en&quot;&gt;TalkBack&lt;/a&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Where’s the stop button?&lt;/strong&gt; Every screen reader provides a way to pause reading.
For example, with VoiceOver, simply tap anywhere on the screen with two fingers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Not so fast!&lt;/strong&gt; Experienced users have their screen reader read text at double or even higher speed.
Especially at the beginning you should slow down the reading speed and adapt it to your individual needs.
With NVDA, for example, you can set the speed with a slider in the settings under “Speech”.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Choose the right voice&lt;/strong&gt;: In the screen reader settings, select the voice you find most agreeable.
Most of the time there are several male and female voices to choose from.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Gestures and Keyboard Shortcuts&lt;/strong&gt;: Screen readers offer a variety of gestures and keyboard shortcuts
that you can use to perform specific actions more quickly. For example, if you swipe left or right with three
fingers when TalkBack is activated, you can select a navigation mode (e.g. headings). Then swipe up or down
with one finger to jump to the previous or next item of that type. This way you can quickly check whether
elements have been implemented with the correct semantic markup.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;At your command!&lt;/strong&gt; Find out the quickest way to turn the screen reader on and off. By default,
NVDA can be started with the key combination CTRL + ALT + N and switched off with INS + Q. On the iPhone,
you must explicitly set VoiceOver as a shortcut in the settings under “Accessibility”. Then you can toggle
the screen reader on and off by triple-pressing the home button.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The most important thing is to give yourself the time you need. Always remember: practice makes perfect.&lt;/p&gt;
&lt;h2 id=&quot;useful-links&quot;&gt;Useful Links&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nvaccess.org/files/nvda/documentation/userGuide.html&quot;&gt;NVDA User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dequeuniversity.com/screenreaders/nvda-keyboard-shortcuts&quot;&gt;NVDA Keyboard Shortcuts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://support.apple.com/guide/iphone/learn-voiceover-gestures-iph3e2e2281/ios&quot;&gt;VoiceOver Gestures&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://support.google.com/accessibility/android/answer/6151827?hl=en&quot;&gt;TalkBack Gestures&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>accessibility</category><category>audit</category><category>NVDA</category><category>screenreader</category><category>TalkBack</category><category>VoiceOver</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_finger_tap_smartphone.jpg" length="0" type="image/jpeg"/></item><item><title>First Steps towards more Accessibility</title><link>https://www.oidaisdes.org/blog/get-started-with-a11y</link><guid isPermaLink="true">https://www.oidaisdes.org/blog/get-started-with-a11y</guid><description>Improve the accessibility of your website or app with high color contrast, semantic markup and captions.</description><pubDate>Fri, 14 Jan 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I know, accessibility can be daunting. Especially when you take your first look at the abundance
of &lt;a href=&quot;https://www.w3.org/WAI/WCAG21/quickref/&quot;&gt;WCAG criteria&lt;/a&gt; and
resources available. My advice: Take a deep breath, pick a topic you’re interested in (e.g. semantic markup) and
improve one thing in your website or app. Accessibility isn’t an “all or nothing” issue! Every single improvement counts.&lt;/p&gt;
&lt;h2 id=&quot;where-to-begin&quot;&gt;Where to begin?&lt;/h2&gt;
&lt;p&gt;Here’s a list of first improvements you can make to your website or app:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Check the color contrast of text, graphical elements and UI components.&lt;/strong&gt; High color contrast especially helps older
people who are &lt;a href=&quot;https://eldertech.org/color-in-designing-technology-for-seniors/&quot;&gt;less able to make out low contrast patterns&lt;/a&gt;.
Related WCAG criteria: &lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html&quot;&gt;1.4.3 Contrast (Minimum)&lt;/a&gt; and
&lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/non-text-contrast.html&quot;&gt;1.4.11: Non-text Contrast&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Interact with your website only using a keyboard.&lt;/strong&gt; Can you navigate to all interactive elements via the tab key? If not,
check if the elements are implemented with the correct semantic markup (e.g. button and link tags). On your smartphone,
&lt;strong&gt;use the screen reader to navigate&lt;/strong&gt; via swiping and check if interactive elements are correctly identified and can be activated.
Related WCAG criteria: &lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/keyboard.html&quot;&gt;2.1.1: Keyboard&lt;/a&gt; and
&lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/name-role-value.html&quot;&gt;4.1.2: Name, Role, Value&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Do your videos offer captions?&lt;/strong&gt; Captions enable people who are deaf or hard of hearing to watch videos.
At the same time, everyone benefits who finds themselves in a situation where they can’t listen to the audio
(e.g. in a crowded subway with no headphones). Related WCAG criteria:
&lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/captions-prerecorded.html&quot;&gt;1.2.2: Captions (Prerecorded)&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>accessibility</category><category>captions</category><category>color</category><category>contrast</category><category>keyboard</category><category>video</category><category>wcag</category><enclosure url="https://www.oidaisdes.org/sharing/social_sharing_woman_in_wheelchair.jpg" length="0" type="image/jpeg"/></item></channel></rss>