<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>blog.damato.design</title><description>Design Systems Hot Takes</description><link>https://blog.damato.design/</link><item><title>62.5%</title><link>https://blog.damato.design/posts/62-5</link><guid isPermaLink="true">https://blog.damato.design/posts/62-5</guid><pubDate>Mon, 30 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;Pixels are an &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units#absolute_length_units&quot;&gt;absolute unit&lt;/a&gt;, they are expected to represent a fixed size and aren’t affected by outside factors (&lt;a href=&quot;https://www.smashingmagazine.com/2021/07/css-absolute-units/&quot;&gt;sort of&lt;/a&gt;). While this sounds like a good thing for design because you can be be sure of the dimensions, the reality is that using pixel values in the web hinders user experience. Layouts become unresponsive, translated content becomes unreadable, and accessibility preferences just aren’t considered. In most cases, we want to avoid absolute units and instead use something more flexible that adapts to the needs of the layout.&lt;/p&gt;
&lt;p&gt;Relative units are &lt;em&gt;related&lt;/em&gt; to something else. An example of a relative unit is percentage and relates to different properties based on where it is used. The &lt;code&gt;rem&lt;/code&gt; is a relative unit which roughly represents the size of the letter “M” in the document. If the document &lt;code&gt;font-size&lt;/code&gt; changes, all areas where this unit is used will also change. The root &lt;code&gt;font-size&lt;/code&gt; can change based on user preference; usually increasing to help folks with vision impairment. There is a &lt;a href=&quot;https://medium.com/@vamptvo/pixels-vs-ems-users-do-change-font-size-5cfb20831773&quot;&gt;not insignificant amount of the population&lt;/a&gt; who leverage the ability to change the &lt;code&gt;font-size&lt;/code&gt; in user settings so we want to ensure this feature of the web is maintained in our experiences. &lt;a href=&quot;https://brokul.dev/detecting-the-default-browser-font-size-in-javascript&quot;&gt;It’s possible to check this out for yourself.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;hocus-pocus&quot;&gt;Hocus pocus&lt;/h2&gt;
&lt;p&gt;There was &lt;a href=&quot;https://clagnut.com/blog/348/&quot;&gt;a trick by Richard Rutter&lt;/a&gt; discovered many years ago which was meant to help folks better understand relative font-size units when coming from pixels. The trick is to set the &lt;code&gt;font-size&lt;/code&gt; of the document to &lt;code&gt;62.5%&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-string-expression)&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    font-size&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 62.5&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;It’s important to know that when this trick was discovered, we didn’t have &lt;code&gt;rem&lt;/code&gt; units at all. The trick was attempting to solve for &lt;code&gt;em&lt;/code&gt; units. These units are scoped to the parent &lt;code&gt;font-size&lt;/code&gt; which can change at any time. So trying to get all of the sizes to behave is a nightmare. Luckily &lt;code&gt;rem&lt;/code&gt; can only be changed in one place.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;The &lt;code&gt;62.5%&lt;/code&gt; &lt;em&gt;looks like&lt;/em&gt; what we like to call a &lt;a href=&quot;https://css-tricks.com/magic-numbers-in-css/&quot;&gt;magic number&lt;/a&gt;; it seems oddly specific. The number is the ratio 10:16 as a percent. The default &lt;code&gt;rem&lt;/code&gt; is 16 pixels, so 1/16th of a &lt;code&gt;rem&lt;/code&gt; equals one pixel. Multiplying by 10 helps keep the font size &lt;em&gt;somewhat&lt;/em&gt; readable (&lt;code&gt;6.25%&lt;/code&gt; is too small, &lt;code&gt;625%&lt;/code&gt; too large). Then the final use of this declaration allows for the following:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    padding&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; .8&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1.6&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;/* 8px 16px */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, it is possible to write &lt;code&gt;rem&lt;/code&gt; in terms of pixels. This provides &lt;a href=&quot;https://uxdesign.cc/why-designers-should-move-from-px-to-rem-and-how-to-do-that-in-figma-c0ea23e07a15&quot;&gt;the benefits of &lt;code&gt;rem&lt;/code&gt;&lt;/a&gt; while maintaining a pixel mental model. &lt;a href=&quot;https://www.aleksandrhovhannisyan.com/blog/62-5-percent-font-size-trick/&quot;&gt;This post by Aleksandr Hovhannisyan&lt;/a&gt; goes into the approach in more detail also mentioning accessibility considerations. Some design systems (eg., &lt;a href=&quot;https://workbench.gusto.com/getting-started/engineers/#css-resets&quot;&gt;Workbench by Gusto&lt;/a&gt;) use the approach to make it “easier” to work with &lt;code&gt;rem&lt;/code&gt; units. So what is so difficult that warrants this approach?&lt;/p&gt;
&lt;p&gt;The fact is that the &lt;code&gt;rem&lt;/code&gt; doesn’t exist in design tools, so a &lt;strong&gt;translation from pixels to &lt;code&gt;rem&lt;/code&gt; must occur&lt;/strong&gt; for an inclusive web experience. Before this approach, designers and engineers would need to figure out what the final &lt;code&gt;rem&lt;/code&gt; number should be based on a formula. Then they would potentially need to repeat that formula every time a new size was needed. In other words, &lt;a href=&quot;https://www.editorx.com/shaping-design/article/font-size&quot;&gt;math is hard and to repeat that math is a waste of time&lt;/a&gt;. It is “easier” for the translation to occur once globally.&lt;/p&gt;
&lt;p&gt;So why would &lt;a href=&quot;https://adactio.com/&quot;&gt;Jeremy Keith&lt;/a&gt; say the following about the author and the approach nearly 20 years later?&lt;/p&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://twitter.com/adactio/status/1523743519034200067&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;Not that he—or anyone else—would recommend it these days!&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://twitter.com/adactio/status/1523743519034200067&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;Jeremy Keith&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;h2 id=&quot;absolutely-arbitrary-font-size&quot;&gt;Absolutely arbitrary font-size&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/toheebdotcom&quot;&gt;Toheeb Ogunbiyi&lt;/a&gt; does a deep dive into the &lt;code&gt;62.5%&lt;/code&gt; approach and has some opinions about thinking in pixels:&lt;/p&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://www.toheeb.com/on/62.5-font-size-trick/&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;Thinking in pixels makes it easy to do the following:&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;Translate UI Design to code.&lt;/li&gt;
&lt;li&gt;Read the code in the editor.&lt;/li&gt;
&lt;li&gt;Troubleshoot the code in the browser.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;This ensures a better development experience. In addition, the mental model is maintained across the team.&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://www.toheeb.com/on/62.5-font-size-trick/&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;Toheeb Ogunbiyi&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;p&gt;What if I said that mental model being maintained is baseless artifact of legacy computer graphic design? 😱&lt;/p&gt;
&lt;p&gt;When you select a pixel font-size, what does it mean? More specifically, what is the difference between &lt;a href=&quot;https://en.wikipedia.org/wiki/Courier_(typeface)&quot;&gt;Courier&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Verdana&quot;&gt;Verdana&lt;/a&gt; at &lt;code&gt;16px&lt;/code&gt;? In practice it’s meant to represent &lt;a href=&quot;https://typography.guru/term/em-square-r46&quot;&gt;the &lt;code&gt;em&lt;/code&gt; square&lt;/a&gt;. In the harsh reality, &lt;a href=&quot;https://graphicdesign.stackexchange.com/questions/4035/what-does-the-size-of-the-font-translate-to-exactly&quot;&gt;it doesn’t really mean anything&lt;/a&gt;. That means we could use 16 pigs, or 1 barn, maybe 8 tulips to talk about &lt;code&gt;font-size&lt;/code&gt; if design tools were prepared to use these units. It actually doesn’t matter as long as the visual result is expected. That’s what we are really doing when curating &lt;code&gt;font-size&lt;/code&gt;. We are tweaking some input and assessing the visual output. When we get something that Looks Good™, we record what the tool says in the input to repeat the visual style in digital media elsewhere.&lt;/p&gt;
&lt;p&gt;So why do we need to use the pixel value so much? It’s because that’s what design tools have decided to use to define the &lt;code&gt;font-size&lt;/code&gt; among other computer graphic properties. If the design tool was to include the &lt;code&gt;rem&lt;/code&gt; as an option, we would have a 1:1 relationship between the design expectation and the engineering execution and no need to require this translation at all! You could speak in terms of &lt;code&gt;rem&lt;/code&gt; right in the tool; no math required. The &lt;a href=&quot;https://twitter.com/SaraSoueidan/status/1619640486305869824&quot;&gt;design tools are the problem&lt;/a&gt; and this “solution” is a community hack for a missing feature.&lt;/p&gt;
&lt;h2 id=&quot;subverting-expectations&quot;&gt;Subverting expectations&lt;/h2&gt;
&lt;p&gt;When the &lt;code&gt;font-size&lt;/code&gt; value is redefined at the &lt;code&gt;html&lt;/code&gt; element, the representation of the &lt;code&gt;rem&lt;/code&gt; is changed for the &lt;em&gt;entire document&lt;/em&gt;. This means that third-party elements could look incorrect; designed with the &lt;code&gt;rem&lt;/code&gt; to expect the browser &lt;code&gt;16px&lt;/code&gt; default. This even includes usage of &lt;code&gt;rem&lt;/code&gt; in the &lt;a href=&quot;https://blog.openreplay.com/shadow-dom--the-ultimate-guide/&quot;&gt;Shadow DOM&lt;/a&gt;. &lt;a href=&quot;https://www.twitter.com/joshwcomeau&quot;&gt;Josh W. Comeau&lt;/a&gt; calls this out:&lt;/p&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://www.joshwcomeau.com/css/surprising-truth-about-pixels-and-accessibility/#the-sixtwofive-trick-13&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;There’s a baseline assumption on the web that &lt;code&gt;1rem&lt;/code&gt; will produce readable text. I don’t wanna mess with that assumption.&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://www.joshwcomeau.com/css/surprising-truth-about-pixels-and-accessibility/#the-sixtwofive-trick-13&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;Josh W. Comeau&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;p&gt;He also mentions that adoption is difficult because it would need to be done all at once. There’s no possibility of incremental enhancement. This also means that deprecating the approach is also troublesome. So you need to be very sure in this decision, more than most others.&lt;/p&gt;
&lt;h2 id=&quot;back-to-base&quot;&gt;Back to base&lt;/h2&gt;
&lt;p&gt;So instead of thinking in terms of pixels for font size, think in terms of a base (or root) size. What is the font size that is most used in the document? This is most likely your body copy. That should be what the &lt;code&gt;rem&lt;/code&gt; represents and exist as the base. Next, any &lt;code&gt;font-size&lt;/code&gt; that you want to set past this should be some proportion from the base. How much larger do you want the headline to be from the base? 1.5x larger? 2x larger? 2.5x larger? Guess what, that’s &lt;code&gt;rem&lt;/code&gt;! If you’ve set your headline to be 2.5x times larger than the base, that’s &lt;code&gt;2.5rem&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-string-expression)&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    font-size&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 2.5&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;/* 2.5x times larger than your base (root) font-size */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the user zooms the content, that relationship is maintained. This is what &lt;a href=&quot;https://twitter.com/andresgalante&quot;&gt;Andrés Galante&lt;/a&gt; says in his article &lt;a href=&quot;https://css-tricks.com/accessible-font-sizing-explained/&quot;&gt;“Accessible Font Sizing, Explained”&lt;/a&gt; at CSS-Tricks:&lt;/p&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://css-tricks.com/accessible-font-sizing-explained/#aa-think-about-proportions-not-size&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;Think about proportions, not size&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://css-tricks.com/accessible-font-sizing-explained/#aa-think-about-proportions-not-size&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;Andrés Galante&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;p&gt;While it’s recommended to &lt;em&gt;not&lt;/em&gt; update the &lt;code&gt;font-size&lt;/code&gt; at &lt;code&gt;html&lt;/code&gt; and maintain the default expectations, setting the size here &lt;a href=&quot;https://taupecat.com/blog/2013/07/17/the-62-5-solution/&quot;&gt;isn’t all bad&lt;/a&gt; as long as it’s made accessible. Just recognize that it does affect &lt;em&gt;all&lt;/em&gt; use of &lt;code&gt;rem&lt;/code&gt; throughout the page where this rule is applied. So reverting this approach later is an exercise of auditing all pages where &lt;code&gt;rem&lt;/code&gt; is used and updating the values where appropriate. For large applications and systems, this could be a monumental task. However, if you’ve kept in mind that the &lt;code&gt;rem&lt;/code&gt; is relating to the &lt;code&gt;font-size&lt;/code&gt; in the usage, it might not be a difficult change. It might even be a feature of the approach. Though, if you use &lt;code&gt;rem&lt;/code&gt; as just another unit because someone said it’s better without understanding why, you might end up fighting &lt;code&gt;rem&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Don’t dislike &lt;code&gt;rem&lt;/code&gt; because you don’t understand it, dislike pixels because you do.&lt;/p&gt;</content:encoded></item><item><title>Accent Color</title><link>https://blog.damato.design/posts/accent-color</link><guid isPermaLink="true">https://blog.damato.design/posts/accent-color</guid><pubDate>Tue, 10 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;The concept of an accent color occurs in modern web design often, especially in minimalistic compositions of black and white. The accent color is typically used to start drawing attention to important elements and tie in with the beginnings of a brand expression. We often see this manifest in rudimentary token systems that might include something like &lt;code&gt;$accent-color&lt;/code&gt; such that this color can be changed to affect an overall mood where appropriate.&lt;/p&gt;
&lt;p&gt;In fact, this very blog uses this approach on each of the articles to indicate how spicy a particular topic is. This is an easy way to keep the overall look of a site consistent across pages, while giving individual pages their own personality.&lt;/p&gt;
&lt;h2 id=&quot;accent-color&quot;&gt;&lt;code&gt;accent-color&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Recently, we received a CSS property called &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/accent-color&quot;&gt;&lt;code&gt;accent-color&lt;/code&gt;&lt;/a&gt;, which is made to affect the color provided by the user-agent and operating system with one provided by the brand through a stylesheet:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-string-expression)&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;checkbox&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;radio&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;range&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;progress&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    accent-color&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; hotpink&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will update the color of some user-interface controls to &lt;code&gt;hotpink&lt;/code&gt; in browsers that support it. This helps convey a consistent brand easily without needing to provide customized controls which might require a lot of reimplementation. Unfortunately, due to the spotty support, teams continue to resort to custom controls to properly convey their brand with custom colors.&lt;/p&gt;
&lt;h2 id=&quot;accentcolor&quot;&gt;&lt;code&gt;AccentColor&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Where &lt;code&gt;accent-color&lt;/code&gt; is a method for a web designer to &lt;em&gt;set&lt;/em&gt; a color for user-interface controls, the &lt;code&gt;AccentColor&lt;/code&gt; keyword is a method for a web designer to &lt;em&gt;get&lt;/em&gt; the current color given to user interface controls… &lt;a href=&quot;#fingerprinting&quot;&gt;sort of&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;At &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/system-color&quot;&gt;the MDN page for system color&lt;/a&gt;, you’ll find other keywords on the page that are meant to provide default color choices for a web page. As an example, the &lt;code&gt;VisitedText&lt;/code&gt; is the purple we’d see as the default color for visited links.&lt;/p&gt;
&lt;p&gt;If you scroll to the bottom of MDN for the Browser compatibility table, you might find something strange:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/browser-compat-accent-color.png&quot; alt=&quot;Browser compatibility table for system color&quot;/&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;AccentColor&lt;/code&gt; (and &lt;code&gt;AccentColorText&lt;/code&gt;) are called out as not supported in many browsers in comparison to the rest of the list. What’s up with that? The answer: &lt;strong&gt;Privacy&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;fingerprinting&quot;&gt;Fingerprinting&lt;/h2&gt;
&lt;p&gt;The introduction of &lt;code&gt;AccentColor&lt;/code&gt; into browsers begins &lt;a href=&quot;https://github.com/w3c/csswg-drafts/issues/7347&quot;&gt;here&lt;/a&gt; in 2022 and everything is going fairly smoothly until August 2023, where Joey Arhar, a engineer working on the Chrome browser for Google, leaves a comment suggesting that implementing this feature could present a new “fingerprinting” vector. This spawns a totally new and separate discussion about &lt;a href=&quot;https://github.com/w3c/csswg-drafts/issues/10372&quot;&gt;Mitigating fingerprinting for AccentColor/AccentColorText&lt;/a&gt; bringing the original discussion to a halt over these concerns.&lt;/p&gt;
&lt;p&gt;So what’s all of this about fingerprinting? &lt;a href=&quot;https://web.dev/learn/privacy/fingerprinting&quot;&gt;Here’s what web.dev says&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Fingerprinting means trying to identify a user when they return to your website, or identifying the same user across different websites.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The idea is that identifying the color assigned to &lt;code&gt;AccentColor&lt;/code&gt; for your device could be a data point in a larger collection that would specifically identify you (or more specifically your device) such that scripts could follow you from site to site. You might see how this could be used from an analytics point-of-view, where you could follow the path of a user from an advertisement all the way to a purchase flow. However, this could also be used in a digital surveillence capacity. Scripts could collect data about a target’s device and then identify how that device travels between collaborative or infected sites.&lt;/p&gt;
&lt;p&gt;This is the reason some of the properties that were once introduced at &lt;code&gt;window.navigator&lt;/code&gt; are now marked as deprecated. It is because they offered too much information that could be used for fingerprinting. If your code is depending on the type of browser or device, it’s possible this is no longer reliable. Instead, you should modify your code to use feature detection instead.&lt;/p&gt;
&lt;p&gt;Importantly, the real problem isn’t the color but the &lt;em&gt;value&lt;/em&gt; that the color represents. There’s no problem with displaying the color to the user. The problem arises when some code attempts to read the value of the given color which could be used as a data point. That’s why the newer discussion considers returning static values for when the color is meant to be retrieved, such as using &lt;code&gt;getComputedStyle()&lt;/code&gt; in JavaScript or if the color was to be rasterized to an HTML &lt;code&gt;&amp;lt;canvas/&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;What isn’t clear yet is how the keyword might work with CSS &lt;code&gt;color-mix()&lt;/code&gt; and this is why I’m heavily interested in the outcome.&lt;/p&gt;
&lt;h2 id=&quot;personalization&quot;&gt;Personalization&lt;/h2&gt;
&lt;p&gt;In my most recent work, I speak about the concept of &lt;strong&gt;influence&lt;/strong&gt;. This means instead of an organization curating tokens precisely, I recommend looking into the idea of influencing existing values with some brand expression. In this way, we don’t specifically say that &lt;code&gt;$body-bg&lt;/code&gt; is exactly &lt;code&gt;#ffffff&lt;/code&gt; but instead we &lt;em&gt;influence&lt;/em&gt; the given color with ours by some amount. What is the given color? In my opinion, it’s the color chosen by the user. How it is chosen can be a separate topic altogether but consider this; imagine if we could support light and dark mode simply by saying “&lt;code&gt;#66ff22&lt;/code&gt; is our brand color” and let the system figure out the rest.&lt;/p&gt;
&lt;p&gt;Here’s a practical example: let’s say I’m trying to convey the brand of Home Depot with their signature orange &lt;code&gt;#ee7125&lt;/code&gt;. Instead of going through all of the tokens, for both light and dark mode, what if instead I only provide this one color and let modern color functions and system colors fill in the rest?&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-string-expression)&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;    /* Set our brand color */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --brand-color&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; #ee7125&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-comment)&quot;&gt;    /* This is needed for system colors to work */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    color-scheme&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; light dark&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-comment)&quot;&gt;    /* Use color-mix to influence the system color */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    background&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; color-mix&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(in oklch&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; Canvas&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--brand-color) 5&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    color&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; color-mix&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(in oklch&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; CanvasText&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--brand-color) 5&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This would tint the background and foreground colors with the &lt;code&gt;--brand-color&lt;/code&gt; by &lt;code&gt;5%&lt;/code&gt;. Importantly, the color supplied by &lt;code&gt;Canvas&lt;/code&gt; and &lt;code&gt;CanvasText&lt;/code&gt; is supplied by the device and browser depending on the user’s settings. As an example, in light mode, we’d expect &lt;code&gt;Canvas&lt;/code&gt; to be a light color. Importantly, you cannot be sure what this color keyword is exactly. As a reiteration, this means we aren’t choosing the color for the background and foreground directly, but we are influencing what is given by the user’s choices with our own orange brand.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;The &lt;code&gt;5%&lt;/code&gt; used above is just used for example purposes. In reality I’d figure &lt;code&gt;Canvas&lt;/code&gt; and &lt;code&gt;CanvasText&lt;/code&gt; wouldn’t need brand influence at all. Instead, I’d consider adjusting actions and controls with some brand influence as they are meant to stand out more than most surfaces. Which system colors to use for those is less straightforward.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;Ultimately, I’d like to see system colors that were closer to the concept of &lt;a href=&quot;/posts/tokens-as-intents/&quot;&gt;intents&lt;/a&gt;. Though I’ve found some sensible replacements in most cases. You can see some of this in action at &lt;a href=&quot;https://system.damato.design&quot;&gt;my system playground&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There’s lots of opporunity for this to fail unfortunately but I believe there’s also opportunity for this to succeed. A user can be responsible for the appropriate general presentation either actively (&lt;a href=&quot;https://blog.codinghorror.com/a-tribute-to-the-windows-31-hot-dog-stand-color-scheme/&quot;&gt;heyo hot dog stand&lt;/a&gt; 🌭) or passively (&lt;a href=&quot;https://www.nngroup.com/articles/generative-ui/&quot;&gt;maybe learning user activity&lt;/a&gt;). While we influence that presentation slightly with our own branding. This needs more experts, especially ones who work with color, to figure out best practices over time.&lt;/p&gt;
&lt;p&gt;Folks that are used to providing highly curated values for their experiences are going to feel uneasy with this. But for those who truly put the user first, we can &lt;a href=&quot;/posts/colors-dont-solve-problems/&quot;&gt;lessen the emphasis on choosing color&lt;/a&gt; and redirect our efforts to providing a better overall experience.&lt;/p&gt;</content:encoded></item><item><title>Against atomic design</title><link>https://blog.damato.design/posts/against-atomic-design</link><guid isPermaLink="true">https://blog.damato.design/posts/against-atomic-design</guid><pubDate>Wed, 25 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;Atomic design as an idea I agree with; parts of your system are built from smaller parts. What I don’t agree with is the image that has been floating around the internet which introduces people to the concept:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/brad-frost-atomic.png&quot; alt=&quot;Atomic design guide showing small parts becoming larger&quot;/&gt;&lt;/p&gt;
&lt;p&gt;If you think about this, how could an organism (a living thing) become a template (a non-living thing)? If you think I’m taking the image too literally; that’s the point. People around the design community have taken the naming convention provided by design as the standard and using it to communicate where something lives within the system.&lt;/p&gt;
&lt;p&gt;So here’s a simple question, where would I find the dropdown component in this system? If you know about atomic design this is probably a molecule. If you &lt;em&gt;don’t know&lt;/em&gt; about atomic design (perhaps like many engineers looking for a component), then it could be a molecule or an organism by process of elimination.&lt;/p&gt;
&lt;p&gt;However, even if you know about atomic design the examples can also conflict. The canonical example of an organism in &lt;a href=&quot;https://bradfrost.com/blog/post/atomic-web-design/&quot;&gt;the original post&lt;/a&gt; is a masthead. However, the masthead could be a reusable template because the megamenu within the masthead could be a organism. The lines become blurry about what exists at each level even for folks who follow atomic design. There’s a lots of room for debate about what a particular part of the interface should be categorized as. That debate will only cause confusion and distract from the purpose of the idea.&lt;/p&gt;
&lt;p&gt;So here’s the easy fix:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/revised-atomic.png&quot; alt=&quot;Atomic design guide showing small parts becoming larger&quot;/&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#naming-is-hard&lt;/strong&gt;. The naming is what hurts the approach.&lt;/p&gt;
&lt;h2 id=&quot;definitions&quot;&gt;Definitions&lt;/h2&gt;
&lt;p&gt;I’m going to also include some definitions that I’ve developed while working with design system people and resources that might help bridge communications across disciplines.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Product teams&lt;/strong&gt;: The group of individual contributors who are responsible for bringing product concepts to life; commonly comprised of designers and developers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Patterns&lt;/strong&gt;: Recommended, content-agnostic compositions that have not yet been formally named or packaged which are meant to host content, interactivity or feedback for product team use.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Components&lt;/strong&gt;: Patterns that have been promoted to reusable packaged resources which simplify the options that the original pattern suggested using internal logic.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fragments&lt;/strong&gt;: Components only meant to be used to compose more complex components. These are not commonly used by members outside of the team responsible for them. An example might be a modal backdrop.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Local Components&lt;/strong&gt;: Components meant to support a specific product or feature.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Universal Components&lt;/strong&gt;: Components meant to support all products and features.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Layouts&lt;/strong&gt;: Reusable compositions for visual arrangement; analogous to the use within artboards.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Templates&lt;/strong&gt;: Reusable compositions for data arrangement; analogous to the use within database schemas.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Modules&lt;/strong&gt;: Components populated and configured by people outside of product teams.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The reason we give names to anything is to share ideas. If the name doesn’t properly identify the idea in a repeatable way; it’s a signal that the name doesn’t support the idea well. My recommendation is to not take the atomic design system naming convention literally but instead to execute on the concept that an interface is a collection of increasing complex compositions. The naming used within the system should be developed so that it meets expectations for most introduced to the system and limits ambiguity.&lt;/p&gt;</content:encoded></item><item><title>Antidatalossconfigurationism</title><link>https://blog.damato.design/posts/antidatalossconfigurationism</link><guid isPermaLink="true">https://blog.damato.design/posts/antidatalossconfigurationism</guid><pubDate>Tue, 08 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;I’m in the middle of deep thought about what a text component looks like. There’s the easy stuff like having the ability to choose the appropriate semantic element. There’s the less obvious stuff, like adding a flag for &lt;a href=&quot;/posts/screenreader-only/&quot;&gt;screenreader only content&lt;/a&gt;. But then there’s something that we tend to overlook, how to manage overflow content.&lt;/p&gt;
&lt;h2 id=&quot;data-loss&quot;&gt;Data loss&lt;/h2&gt;
&lt;p&gt;It’s not uncommon for someone to choose the solution of clipping the content, maybe in the form of an ellipsis. We even have more options coming about &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/line-clamp&quot;&gt;when those ellipsis appear&lt;/a&gt;. The problem with approaches that include &lt;code&gt;overflow: hidden;&lt;/code&gt; is that the content is no longer clearly accessible. This goes against a core principle of mine: if you place it on the page, that means it is important. There should be no condition that obstructs that element in any way. Otherwise that can introduce data loss. Adding ellipsis is not an inclusive solution to large blocks of text. Instead, we’ll need to ensure the text remains readable while balancing the expectations of the layout.&lt;/p&gt;
&lt;h2 id=&quot;properties&quot;&gt;Properties&lt;/h2&gt;
&lt;p&gt;There’s several CSS properties that are directly related to the way text flows on a webpage. We’ll go over each of the properties below but first a few definitions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Whitespace&lt;/strong&gt; refers to characters that provide space between other characters.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Segment breaks&lt;/strong&gt; are characters that cause text to break onto new lines (eg., line feed).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hard breaks&lt;/strong&gt; (aka: forced line break) will always cause the text to break onto a new line, even if it is not necessary to do so.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Soft breaks&lt;/strong&gt; will cause text to break to a new line only if necessary. Where these can occur are called soft wrap opportunities.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Line box&lt;/strong&gt; describes the inline formatted box, typically used to contain text. The size of this box depends on the content and the available size of its ancestors.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CJK&lt;/strong&gt; is short for Chinese/Japanese/Korean used to describe text that has a different ruleset for when strings are allowed to break.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;white-space&quot;&gt;&lt;code&gt;white-space&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;This property has been around for a while, but recently it has been altered to host separate properties. Overall, this property and its related new properties are meant to handle how whitespace characters effect the surrounding text.&lt;/p&gt;
&lt;p&gt;First, the &lt;code&gt;white-space-collapse&lt;/code&gt; property has the following possible values:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;collapse&lt;/code&gt; says that all whitespace should be collapsed. How whitespace is collapsed &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/white-space-collapse#collapsing_of_white_space&quot;&gt;follows several algorithmic steps&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;preserve&lt;/code&gt; says whitespace and segment break characters are perserved. This is commonly seen as the default in the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/pre&quot;&gt;&lt;code&gt;&amp;lt;pre/&amp;gt;&lt;/code&gt; HTML element&lt;/a&gt; style.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;preserve-breaks&lt;/code&gt; says only preserve segment breaks, whitespace characters are collapsed.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;preserve-spaces&lt;/code&gt; does the opposite of &lt;code&gt;preserve-breaks&lt;/code&gt; by allowing segment breaks to be collapsed and perserve whitespace as written in source.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;break-spaces&lt;/code&gt; is the most unique of the values with a more specific set of rules for how whitespace is perserved.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember that &lt;code&gt;white-space-collapse&lt;/code&gt; is only one part of the &lt;code&gt;white-space&lt;/code&gt; property. The other part is &lt;code&gt;text-wrap-mode&lt;/code&gt; which only has two values, &lt;code&gt;wrap&lt;/code&gt; and &lt;code&gt;nowrap&lt;/code&gt;. As you might expect, you’ll primarly want to have &lt;code&gt;text-wrap-mode: wrap&lt;/code&gt; and this is the default.&lt;/p&gt;
&lt;p&gt;When considering the keyword options provided by the original &lt;code&gt;white-space&lt;/code&gt; property, it’s not immediately clear how they align to these values:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;normal&lt;/code&gt; is &lt;code&gt;white-space-collapse: collapse; text-wrap-mode: wrap&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pre&lt;/code&gt; is &lt;code&gt;white-space-collapse: preserve; text-wrap-mode: nowrap&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pre-line&lt;/code&gt; is &lt;code&gt;white-space-collapse: preserve-breaks; text-wrap-mode: wrap&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pre-wrap&lt;/code&gt; is &lt;code&gt;white-space-collapse: preserve; text-wrap-mode: wrap&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;There is no keyword analog under &lt;code&gt;white-space&lt;/code&gt; to get &lt;code&gt;white-space-collapse: preserve-spaces&lt;/code&gt; behavior. At the time of this writing, this is only available in Firefox.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;h3 id=&quot;text-wrap&quot;&gt;&lt;code&gt;text-wrap&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;To make things more confusing, &lt;code&gt;text-wrap&lt;/code&gt; is also a shorthand. We already saw one of the properties &lt;code&gt;text-wrap-mode&lt;/code&gt; which determines if the text is allowed to wrap or not. The newer part to this is &lt;code&gt;text-wrap-style&lt;/code&gt; which has added many of the fancy algorithmic ways that text can wrap based on the number of characters. Here are the values for this property:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;auto&lt;/code&gt; wraps the text in the most performant way and ignores the number of characters. This is the default.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;balance&lt;/code&gt; attempts to wrap in away that keeps the number of characters roughly equal amongst the lines of text. This is best used for headlines.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pretty&lt;/code&gt; is similar to balance but favors layout over speed. This is best used for paragraphs of text.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;stable&lt;/code&gt; is meant to be applied in areas where the user is editing content and wrapping should be kept to a minimum during this time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://csswizardry.com/&quot;&gt;Harry Roberts&lt;/a&gt; &lt;a href=&quot;https://x.com/csswizardry/status/1725543814587134435&quot;&gt;posted some benchmarks&lt;/a&gt; on using the newer &lt;code&gt;text-wrap&lt;/code&gt; values. The setup was a page with 10,000 &lt;code&gt;&amp;lt;p/&amp;gt;&lt;/code&gt; elements which, by default, have orphans. Here’s what he found:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Baseline – 1,186ms&lt;/li&gt;
&lt;li&gt;&lt;code&gt;text-wrap: balance&lt;/code&gt;: 1,224ms (38ms/3.2% longer)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;text-wrap: pretty&lt;/code&gt;: 1,310ms (124ms/10.5% longer)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;He said that impact on &lt;code&gt;balance&lt;/code&gt; was almost zero, while &lt;code&gt;pretty&lt;/code&gt; is more noticeable. The reality is that you most likely won’t have 10,000 paragraphs on your page.&lt;/p&gt;
&lt;p&gt;The properties so far are only configuring how the whitespace characters behave in a block of text. None of these properties will affect the strings of characters that typically behave as words. The following properties are meant to target when these strings are meant to break and avoid poor layout artifacts.&lt;/p&gt;
&lt;h3 id=&quot;overflow-wrap&quot;&gt;&lt;code&gt;overflow-wrap&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;overflow-wrap&lt;/code&gt; property helps tell the browser when it should insert line breaks in otherwise unbreakable strings of text to prevent overflowing. This is an alias of the &lt;code&gt;word-wrap&lt;/code&gt; property. Originally, this only allowed two values &lt;code&gt;normal&lt;/code&gt; the default which keeps strings in tact and &lt;code&gt;break-word&lt;/code&gt; which will break words &lt;em&gt;sometimes&lt;/em&gt;. When a word is meant to break depends on the width of the container and where soft breaks can exist. This is usually very helpful for places where a long URL is written that needs to be broken to maintain a reasonable text layout.&lt;/p&gt;
&lt;p&gt;The newer value option is &lt;code&gt;anywhere&lt;/code&gt; which is typically less desirable as soft wrap characters are also used to determine how big the line box should be. This will allow the box to be much smaller instead of trying to fill the box as is normally expected.&lt;/p&gt;
&lt;h3 id=&quot;word-break&quot;&gt;&lt;code&gt;word-break&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Continuing with the theme of confusingly similar CSS properties, &lt;code&gt;word-break&lt;/code&gt; is a property that determines what happens when a string would overflow outside of its container. To make things worse, one of the values here is an override to &lt;code&gt;overflow-wrap&lt;/code&gt;. We’ll start with that one:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;break-word&lt;/code&gt; is identical to &lt;code&gt;overflow-wrap: anywhere&lt;/code&gt; and takes priority over any other value provided to &lt;code&gt;overflow-wrap&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;normal&lt;/code&gt; says to use normal line break rules which may also break between CJK characters.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;break-all&lt;/code&gt; will cause a break to occur at the place where overflow would occur.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;keep-all&lt;/code&gt; same as &lt;code&gt;normal&lt;/code&gt; except CJK characters will also not break.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;auto-phrase&lt;/code&gt; same as &lt;code&gt;normal&lt;/code&gt; but analysizes the language to avoid breaking natural phrases.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A question you might have, what’s the difference between all of these properties? They all look like they handle the same sort of consideration for breaking strings of text. The CSSWG has an &lt;a href=&quot;https://drafts.csswg.org/css-text/#line-breaking&quot;&gt;excellent breakdown of the differences&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;line-break&lt;/code&gt; property allows choosing various levels of “strictness” for line breaking restrictions.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;word-break&lt;/code&gt; property controls what types of letters are glommed together to form unbreakable “words”, causing CJK characters to behave like non-CJK text or vice versa.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;hyphens&lt;/code&gt; property controls whether automatic hyphenation is allowed to break words in scripts that hyphenate.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;overflow-wrap&lt;/code&gt; property allows the user-agent to take a break anywhere in otherwise-unbreakable strings that would otherwise overflow.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;On top of the other properties that we didn’t cover, there’s a lot more detail within that page about how line breaks are expected to work. I’ve made a little playground to see how the properties would affect text samples combined from MDN examples:&lt;/p&gt;
&lt;iframe height=&quot;500&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;Antidatalossconfigurationism&quot; src=&quot;https://codepen.io/fauxserious/embed/jEbNMge?result&quot; frameborder=&quot;no&quot; loading=&quot;lazy&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/fauxserious/pen/jEbNMge&quot;&gt;
Antidatalossconfigurationism&lt;/a&gt; by Donnie D’Amato (&lt;a href=&quot;https://codepen.io/fauxserious&quot;&gt;@fauxserious&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;recommendations&quot;&gt;Recommendations&lt;/h2&gt;
&lt;p&gt;Based on all of this, here’s how I’d try making an API for a text component when it comes to avoiding data loss. Here’s my considerations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a &lt;code&gt;wrap&lt;/code&gt; flag with the following values:
&lt;ul&gt;
&lt;li&gt;(default) if the tag name used expects a certain &lt;code&gt;text-wrap-style&lt;/code&gt; value, use that style. For example, &lt;code&gt;balance&lt;/code&gt; for shorter text and &lt;code&gt;pretty&lt;/code&gt; for longer text.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;true&lt;/code&gt; is the same as &lt;code&gt;text-wrap-mode: wrap&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;false&lt;/code&gt; is the same as &lt;code&gt;text-wrap-mode: nowrap&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Create a &lt;code&gt;break&lt;/code&gt; flag with the following values:
&lt;ul&gt;
&lt;li&gt;(default) sets &lt;code&gt;overflow-wrap: break-word&lt;/code&gt; on text by default. This will allow the presence of long URL to break nicely when within the text. &lt;a href=&quot;https://www.joshwcomeau.com/&quot;&gt;Josh Comeau&lt;/a&gt; includes this in &lt;a href=&quot;https://www.joshwcomeau.com/css/custom-css-reset/&quot;&gt;his CSS reset&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;true&lt;/code&gt; is the same as &lt;code&gt;word-break: break-all&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;false&lt;/code&gt; is the same as &lt;code&gt;word-break: keep-all&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here’s what the CSS might look like:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.text&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    overflow&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; visible &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;!important&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    overflow-wrap&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; break-word&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-color-text)&quot;&gt;    &amp;amp;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;where(h1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; h2&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; h3&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; h4&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; h5&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; h6&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; dt&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; legend&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; label&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; th&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        text-wrap&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; balance&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-color-text)&quot;&gt;    &amp;amp;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;:where&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; li&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; figcaption&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; dd&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; summary&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; caption&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        text-wrap&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; pretty&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-color-text)&quot;&gt;    &amp;amp;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;:where&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;textarea&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;contenteditable&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        text-wrap&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; stable&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-color-text)&quot;&gt;    &amp;amp;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;:where&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;data-wrap&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;:where&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;pre&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; kbd&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        text-wrap&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; pre-wrap&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-color-text)&quot;&gt;    &amp;amp;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;:where&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;data-wrap&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        text-wrap&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; nowrap&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-color-text)&quot;&gt;    &amp;amp;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;:where&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;data-break&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        word-break&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; break-all&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-color-text)&quot;&gt;    &amp;amp;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;:where&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;data-break&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        word-break&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; keep-all&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’m using the keyword value for &lt;code&gt;text-wrap&lt;/code&gt; over the shorthand because it’s easier to update this value instead of unsetting it to reapply in some cases. This allows us to leverage the default of &lt;code&gt;text-wrap-mode: wrap&lt;/code&gt; for most elements.&lt;/p&gt;
&lt;p&gt;The elements I’ve chosen to receive &lt;code&gt;text-wrap-style&lt;/code&gt; are based on their expected content. Elements that expect shorter amounts of content receive &lt;code&gt;balance&lt;/code&gt; while elements that expect longer amounts use &lt;code&gt;pretty&lt;/code&gt;. Note that these are targeting elements that would normally have content as their direct children. While you could put &lt;code&gt;pretty&lt;/code&gt; on sectioning content for it to cascade, it’s more performant to be more specific.&lt;/p&gt;
&lt;p&gt;If you were paying attention, you’ll notice that there’s a lot of property values that we went over which are missing from the API. The reason is that they’re probably not going to be useful in day-to-day web development. This isn’t meant to be a CSS reset, this is an opinionated setup for what I believe would be a text component that allows for some customizability while keeping the options limited.&lt;/p&gt;
&lt;p&gt;This includes my own rule-breaking for use of &lt;code&gt;!important&lt;/code&gt; in this case to call out that hiding overflow on text is a bad practice. &lt;a href=&quot;/posts/out-of-order/&quot;&gt;Makes me want to set &lt;code&gt;z-index: auto !important&lt;/code&gt;&lt;/a&gt; on &lt;a href=&quot;/posts/hottest-box/&quot;&gt;all my elements&lt;/a&gt; too.&lt;/p&gt;</content:encoded></item><item><title>Astro RSS MDX</title><link>https://blog.damato.design/posts/astro-rss-mdx</link><guid isPermaLink="true">https://blog.damato.design/posts/astro-rss-mdx</guid><pubDate>Sun, 18 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;I’ve been using Astro for a long time. The developer experience includes all the best parts from the way I learned web development nearly 30 years ago. The stuff that was missing back then is intuitively included, like HTML templating without the need for a heavy framework. I’ve since moved all the personal projects I’m currently developing onto an Astro stack.&lt;/p&gt;
&lt;p&gt;However, there’s been one thing that was always missing from the Astro ecosystem. Rendering full content MDX in your RSS feed.&lt;/p&gt;
&lt;h2 id=&quot;astros-recommendation&quot;&gt;Astro’s recommendation&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.astro.build/en/guides/rss/&quot;&gt;From the docs&lt;/a&gt;, the general idea is to use &lt;a href=&quot;https://www.npmjs.com/package/@astrojs/rss&quot;&gt;Astro’s RSS package&lt;/a&gt; to create the feed. This isn’t doing anything too special itself. It leverages the &lt;code&gt;src/pages&lt;/code&gt; directory to statically generate XML content based on your collections. Here’s the “whole” example from their docs:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; rss &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;@astrojs/rss&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { getCollection } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;astro:content&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; GET&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(context) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; blog&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; getCollection&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;blog&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; rss&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    title&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;Buzz’s Blog&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    description&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;A humble Astronaut’s guide to the stars&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    site&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; context&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.site&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    items&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; blog&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.map&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;((post) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; ({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      title&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; post&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.title&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      pubDate&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; post&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.pubDate&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      description&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; post&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.description&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      customData&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; post&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.customData&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      link&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; `/blog/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;post&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.slug&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;/`&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    }))&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I put the word “whole” in quotes because you might notice that the post content is missing from the feed. Some folks prefer this choice to drive traffic to their website. Personally, I’m old school and would rather folks read my content in whatever medium they feel most comfortable. That’s why it was very important to include the full content in my feed.&lt;/p&gt;
&lt;p&gt;While Astro does have a &lt;a href=&quot;https://docs.astro.build/en/guides/rss/#including-full-post-content&quot;&gt;section about rendering full page content&lt;/a&gt;, it is limited to vanilla Markdown. It does not include an approach to handle the full MDX documented. In fact, it suggests using an entirely different rendering engine. This has been a big thorn in the side for folks who have dynamic MDX content looking to migrate to Astro from other ecosystems. This is because the only way to render that content is by using the following:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;astro&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { getEntry } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;astro:content&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;slug&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; Astro&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.params;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; entry&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; getEntry&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;posts&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; slug);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Content&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; entry&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.render&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Content&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That &lt;code&gt;&amp;lt;Content/&amp;gt;&lt;/code&gt; component can only be rendered within the context of a &lt;code&gt;.astro&lt;/code&gt; file. Now, you might think you could just render that content to HTML and then fetch the result. With some finesse, &lt;a href=&quot;https://github.com/ddamato/astro-mdx-rss&quot;&gt;you can get this to work&lt;/a&gt; in local development, but a statically generated site will have problems. This is most likely due to a race condition, or the order in which data is rendered. Either way, there hasn’t been a clear approach to render MDX in Astro RSS feeds for a while.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;&lt;a href=&quot;https://github.com/withastro/roadmap/discussions/881&quot;&gt;I still believe&lt;/a&gt; providing an API that suggests the content type of a file would be helpful. Similar to how you can &lt;a href=&quot;https://docs.astro.build/en/basics/astro-pages/#page-partials&quot;&gt;render a partial file&lt;/a&gt; using &lt;code&gt;export const partial = true;&lt;/code&gt; for frameworks like &lt;a href=&quot;https://htmx.org/&quot;&gt;HTMX&lt;/a&gt;. Then we could render XML from a &lt;code&gt;.astro&lt;/code&gt; file more directly.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;Luckily, one of the more recent releases of Astro introduces an approach that can get us what we’re looking for.&lt;/p&gt;
&lt;h2 id=&quot;astro-containers&quot;&gt;Astro Containers&lt;/h2&gt;
&lt;p&gt;In &lt;a href=&quot;https://astro.build/blog/astro-490/&quot;&gt;v4.9 of Astro&lt;/a&gt;, a new experimental Container API was introduced. The benefit of this API is the ability to render Astro components outside of the normal Astro context, specifically outside of &lt;code&gt;.astro&lt;/code&gt; files. This is exactly what we need to get the content into a normal Javascript file.&lt;/p&gt;
&lt;p&gt;At first, this was not a straightforward process. We still needed a &lt;code&gt;.astro&lt;/code&gt; file to help render the special &lt;code&gt;&amp;lt;Content/&amp;gt;&lt;/code&gt; element. Soon afterward, the setup to do this became a lot cleaner which is what I’ll show in this post.&lt;/p&gt;
&lt;p&gt;We’ll start with a &lt;code&gt;/pages/feed.xml.js&lt;/code&gt; file. This is similar to what was provided in the first example, and you can certainly use Astro’s RSS package to help construct the feed. However, to get the MDX rendering, you’re going to need some additional helpers. Let’s go through the file by each section, first the imports:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { experimental_AstroContainer &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; AstroContainer } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;astro/container&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { getContainerRenderer &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; getMDXRenderer } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;@astrojs/mdx&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { loadRenderers } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;astro:container&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { getCollection } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;astro:content&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; rss &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;@astrojs/rss&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first line imports the new Container API, we’ll use this to create a new Astro context. The second line comes from the &lt;a href=&quot;https://www.npmjs.com/package/@astrojs/mdx&quot;&gt;&lt;code&gt;@astrojs/mdx&lt;/code&gt; package&lt;/a&gt;, and this will tell the container API how to render the data. The next import is used to load the renderers. For whatever reason, this isn’t included in the container API.&lt;/p&gt;
&lt;p&gt;The last two imports should be familiar, importing the &lt;code&gt;getCollection&lt;/code&gt; method from &lt;code&gt;astro:content&lt;/code&gt; and the &lt;code&gt;rss&lt;/code&gt; builder from &lt;code&gt;@astrojs/rss&lt;/code&gt;. Now we’re going to put those imports to work:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; GET&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(context) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; renderers&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; loadRenderers&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;getMDXRenderer&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;()]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; container&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; AstroContainer&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.create&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({ renderers });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; posts&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; getCollection&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;posts&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; items&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; post&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; of&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; posts) { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;/* Next part will be here */&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; rss&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        title&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;My blog&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        description&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;All my thoughts&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        site&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; context&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.site&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        items&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First, we load the MDX renderer. Then we pass the result of that into the &lt;code&gt;.create()&lt;/code&gt; method for making an Astro Container. Then we do a standard &lt;code&gt;getCollection()&lt;/code&gt; for the posts. If you need to filter posts for some reason, make sure to also do that here before processing in the upcoming for loop. We’re using a for loop instead of a functional process because we’ll need to do some async work in the loop. After all the items are processed, we’ll write the feed using the &lt;code&gt;@astrojs/rss&lt;/code&gt; rendering function. Let’s look at what’s inside the loop:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Content&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; post&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.render&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; content&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; container&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.renderToString&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(Content);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; link&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; URL&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;`/posts/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;post&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.slug&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; context&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.origin)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.toString&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;();    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;items&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.push&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;post&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.data&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; link&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; content });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Assuming that your frontmatter matches the expected schema for &lt;code&gt;@astrojs/rss&lt;/code&gt;, the only other keys you’ll need to provide are &lt;code&gt;link&lt;/code&gt; and &lt;code&gt;content&lt;/code&gt;. You can see how I construct the &lt;code&gt;link&lt;/code&gt; by using the &lt;code&gt;context.url.origin&lt;/code&gt;. This helps with local development.&lt;/p&gt;
&lt;p&gt;Our real focus is the &lt;code&gt;content&lt;/code&gt; output. In here, we do something similar to how we might render the &lt;code&gt;&amp;lt;Content/&amp;gt;&lt;/code&gt; element in a &lt;code&gt;.astro&lt;/code&gt; file. However, then we send the output of that to the &lt;code&gt;container.renderToString()&lt;/code&gt; method. The result of that is regular HTML that we can pipe directly into the &lt;code&gt;rss()&lt;/code&gt; method at the end of the function. Here’s the whole file:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { experimental_AstroContainer &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; AstroContainer } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;astro/container&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { getContainerRenderer &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; getMDXRenderer } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;@astrojs/mdx&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { loadRenderers } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;astro:container&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { getCollection } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;astro:content&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; rss &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;@astrojs/rss&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; GET&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(context) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; renderers&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; loadRenderers&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;getMDXRenderer&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;()]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; container&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; AstroContainer&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.create&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({ renderers });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; posts&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; getCollection&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;posts&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; items&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; post&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; of&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; posts) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;        const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Content&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; post&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.render&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;        const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; content&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; container&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.renderToString&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(Content);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;        const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; link&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; URL&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;`/posts/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;post&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.slug&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; context&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.origin)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.toString&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;();    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        items&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.push&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;post&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.data&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; link&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; content });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; rss&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        title&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;My blog&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        description&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;All my thoughts&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        site&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; context&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.site&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        items&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Again, you’ll probably want to add some additional metadata to your feed, maybe filter and sort the posts too. You could probably construct that data in a similar way to the approach taken for &lt;code&gt;link&lt;/code&gt; above. This is basically how I create &lt;a href=&quot;/feed.xml&quot;&gt;the feed at this very site&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Hopefully, this helps folks with the final steps in migrating their blog to Astro. From here, the sky’s the limit!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;EDIT (2025-01-30):&lt;/strong&gt; I’ve had a few people reach out about this post helping them get full content which is great! However, Astro did change part of the API in v5, &lt;a href=&quot;https://docs.astro.build/en/guides/upgrade-to/v5/#updating-existing-collections&quot;&gt;specifically the way you render content&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Previously, a &lt;code&gt;.render()&lt;/code&gt; would exist on the Collection Entry. Calling that method would return a &lt;code&gt;&amp;lt;Content/&amp;gt;&lt;/code&gt; element; the thing that was so hard to resolve outside of &lt;code&gt;.astro&lt;/code&gt; files.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;astro&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { getEntry } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;astro:content&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; post&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; getEntry&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;blog&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; params&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.slug);&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:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Content&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; headings&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; post&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.render&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Content&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now in v5, there’s a &lt;code&gt;render&lt;/code&gt; function available as an import from &lt;code&gt;astro:content&lt;/code&gt;. You’ll want to use that to get the &lt;code&gt;&amp;lt;Content/&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;astro&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { getEntry&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; render } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;astro:content&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; post&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; getEntry&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;blog&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; params&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.slug);&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:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Content&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; headings&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; render&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(post);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Content&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So the new snippet should look &lt;em&gt;something&lt;/em&gt; like this for v5.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { experimental_AstroContainer &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; AstroContainer } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;astro/container&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { getContainerRenderer &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; getMDXRenderer } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;@astrojs/mdx&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { loadRenderers } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;astro:container&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { getCollection&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; render } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;astro:content&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; rss &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;@astrojs/rss&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; GET&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(context) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; renderers&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; loadRenderers&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;getMDXRenderer&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;()]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; container&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; AstroContainer&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.create&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({ renderers });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; posts&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; getCollection&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;posts&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; items&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; post&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; of&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; posts) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;        const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Content&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; render&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(post);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;        const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; content&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; container&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.renderToString&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(Content);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;        const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; link&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; URL&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;`/posts/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;post&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.slug&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; context&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.origin)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.toString&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;();    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        items&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.push&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;post&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.data&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; link&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; content });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; rss&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        title&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;My blog&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        description&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;All my thoughts&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        site&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; context&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.site&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        items&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I haven’t tested this since my blog is still on v4.11, so your mileage may vary. Good luck!&lt;/p&gt;</content:encoded></item><item><title>Avoiding tokens</title><link>https://blog.damato.design/posts/avoiding-tokens</link><guid isPermaLink="true">https://blog.damato.design/posts/avoiding-tokens</guid><pubDate>Mon, 24 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;The design systems community was buzzing a few days ago with the announcement of version 2 of the Salesforce Lightning Design System (SLDS). &lt;a href=&quot;https://www.linkedin.com/posts/fauxserious_lightning-design-system-2-activity-7298413367847780352-c46N&quot;&gt;I shared the link to the new documentation on LinkedIn&lt;/a&gt; and the engagement has been significant.&lt;/p&gt;
&lt;p&gt;As someone who has visited dozens of design system documentation sites, there’s certain things I tend to look for when perusing the content. One of those things is how the team handles design tokens. Design tokens are a fundamental feature of what we do, because this unlocks the ability to update the presentation of an experience with less friction. In fact, the term design tokens originated from SLDS many years ago.&lt;/p&gt;
&lt;p&gt;That’s why it was so surprising to not find a page dedicated to design tokens in the new version. The term design tokens is mostly absent from the site, except for this quote found on the front page.&lt;/p&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://www.lightningdesignsystem.com/2e1ef8501/p/85bd85-lightning-design-system-2&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;SLDS 2 prioritizes CSS custom properties as the visual language and decreases the usage of design tokens.&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://www.lightningdesignsystem.com/2e1ef8501/p/85bd85-lightning-design-system-2&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;SLDS 2&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;/images/but-why.webp&quot; alt=&quot;Ryan Reynolds meme asking &amp;#34;But why?&amp;#34;&quot;/&gt;&lt;/p&gt;
&lt;p&gt;I aimed to find out.&lt;/p&gt;
&lt;h2 id=&quot;the-problem-theyre-solving&quot;&gt;The problem they’re solving&lt;/h2&gt;
&lt;p&gt;Conversations sparked at the LinkedIn post as well as within the Design Systems Slack where I first saw the link. Alan Weibel, UX Architect at Salesforce, was responding in both places. In all of the discussion, his response to Brad Frost made things more clear.&lt;/p&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://www.linkedin.com/feed/update/urn:li:activity:7298413367847780352?commentUrn=urn%3Ali%3Acomment%3A%28activity%3A7298413367847780352%2C7298461710372270080%29&amp;replyUrn=urn%3Ali%3Acomment%3A%28activity%3A7298413367847780352%2C7298742749405622273%29&amp;dashCommentUrn=urn%3Ali%3Afsd_comment%3A%287298461710372270080%2Curn%3Ali%3Aactivity%3A7298413367847780352%29&amp;dashReplyUrn=urn%3Ali%3Afsd_comment%3A%287298742749405622273%2Curn%3Ali%3Aactivity%3A7298413367847780352%29&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;…I think it depends on how you define design tokens.&lt;/p&gt;&lt;p&gt;If the definition is design tokens are variables (tokens) for design system values, then yes, styling hooks are the same and come with a name-value pair.&lt;/p&gt;&lt;p&gt;If that definition comes with expectations of the specifications in W3C drafts or common implementations of design tokens, then it is not the same. They’re a completely different format that is web first, non-web second.&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://www.linkedin.com/feed/update/urn:li:activity:7298413367847780352?commentUrn=urn%3Ali%3Acomment%3A%28activity%3A7298413367847780352%2C7298461710372270080%29&amp;replyUrn=urn%3Ali%3Acomment%3A%28activity%3A7298413367847780352%2C7298742749405622273%29&amp;dashCommentUrn=urn%3Ali%3Afsd_comment%3A%287298461710372270080%2Curn%3Ali%3Aactivity%3A7298413367847780352%29&amp;dashReplyUrn=urn%3Ali%3Afsd_comment%3A%287298742749405622273%2Curn%3Ali%3Aactivity%3A7298413367847780352%29&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;Alan Weibel, Salesforce UX Architect&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;p&gt;This highlighted the issue. The team at Salesforce has considered the use of the word “design tokens” to strictly mean the artifacts coming from the &lt;a href=&quot;https://www.designtokens.org/&quot;&gt;DTCG&lt;/a&gt; work. Meanwhile, the community has more commonly considered design tokens to simply be the name-value pairing for design purposes. In other words, at Salesforce “design tokens” equals DTCG specification while outside of Salesforce “design tokens” equals name-value pairings.&lt;/p&gt;
&lt;p&gt;So they’ve decided to explicitly distance themselves from the evolving specification but that still doesn’t answer the question of “why?” Here’s another quote from Alan, this time from the Design Systems Slack:&lt;/p&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://design-systems.slack.com/archives/C576NLX2A/p1740160012109289?thread_ts=1740077164.460439&amp;cid=C576NLX2A&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;Design tokens are very helpful for a lot of teams. They just aren’t super helpful for Salesforce. It was an extra step to create tokens to be used across multiple frameworks when 99% of Salesforce is on a single platform—the web. &lt;em&gt;Even our native mobile apps use webviews inside of the native wrapper.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;We ended up using a web standard, CSS custom properties, as the name/value pair instead of design tokens. These style hooks are a lot easier to manage in both code and tooling. If folks need this CSS for a non-web application, then they can use the THEO tool.&lt;/p&gt;&lt;p&gt;In the end, people still get name/value pairs for all the frameworks but it’s less complex and easier to manage for our platform&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://design-systems.slack.com/archives/C576NLX2A/p1740160012109289?thread_ts=1740077164.460439&amp;cid=C576NLX2A&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;Alan Weibel, Salesforce UX Architect&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;p&gt;There’s a few notes that I take away from this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It was easier for the team to write CSS Custom Properties instead of requiring a process to turn non-CSS into CSS.&lt;/li&gt;
&lt;li&gt;They opted for a solid web standard over the more tumultuous DTCG specification.&lt;/li&gt;
&lt;li&gt;The team now focused primarily on the web, so supporting other platforms was considered overkill.&lt;/li&gt;
&lt;li&gt;If some team needs to transform the CSS into non-CSS, they had an answer for that need using &lt;a href=&quot;https://github.com/salesforce-ux/theo&quot;&gt;THEO&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;how-to-fix-this&quot;&gt;How to fix this&lt;/h2&gt;
&lt;p&gt;The community had a very similar response to &lt;a href=&quot;https://www.youtube.com/watch?v=1ONxxlJnvdM&quot;&gt;Figma’s variables&lt;/a&gt;. When the new feature was announced at Config in 2023, the slide showed the word “design tokens” crossed out. Certainly meant to cause a stir amongst the crowd before announcing variables which work very similar in concept. The team made a conscious decision to not name them design tokens but why? Jacob Miller answers that question in the Design Systems Slack:&lt;/p&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://design-systems.slack.com/archives/C56V07C4U/p1687366044434609?thread_ts=1687364523.348789&amp;cid=C56V07C4U&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;…If we tailor-made a solution for design tokens, we’d end up with disparate systems for a bunch of other features that have similar requirements, such as translation strings or conditional prototyping logic.&lt;/p&gt;&lt;p&gt;Rather than do that, we wanted two things: A more unified experience, and more alignment with code. In the same way that you can use css variables to implement design tokens, we wanted that with Figma as well.&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://design-systems.slack.com/archives/C56V07C4U/p1687366044434609?thread_ts=1687364523.348789&amp;cid=C56V07C4U&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;Jacob Miller, Figma Product Manager&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;/posts/spicy-specifications/&quot;&gt;I wrote about why they were different&lt;/a&gt; when variables were first released, along with other design token metadata options at the time.&lt;/p&gt;
&lt;p&gt;The difference between Salesforce and Figma is that &lt;a href=&quot;https://help.figma.com/hc/en-us/articles/18490793776023-Update-1-Tokens-variables-and-styles&quot;&gt;Figma has documentation which speaks about design tokens&lt;/a&gt; and how to implement them within their ecosystem. This makes it easier for folks expecting design tokens to be supported and how to transition those folks into the specific changes within Figma to do similar things.&lt;/p&gt;
&lt;p&gt;This is where the decision for the public documentation of the SLDS breaks down. The lack of design tokens or a path for transitioning makes it hard for folks expecting to see the concept. SLDS does have name-value pairs in a similar way to how most of us think of design tokens, they’ve just renamed the concept to &lt;a href=&quot;https://www.lightningdesignsystem.com/2e1ef8501/p/319e5f-styling-hooks&quot;&gt;Styling Hooks&lt;/a&gt;. This is the same as naming your carousel component “Fred”. It might work for your internal team, but cause friction for anyone coming at it for the first time, externally or internally.&lt;/p&gt;
&lt;p&gt;I’d recommend that the SLDS team explain in their public documentation how folks looking for design tokens can transition to styling hooks. At best, define “design tokens” more generally as the community currently does or make mention in &lt;a href=&quot;https://www.salesforce.com/blog/what-are-styling-hooks/&quot;&gt;their blog post&lt;/a&gt; that the DTCG was too complex for their needs at this time.&lt;/p&gt;
&lt;h2 id=&quot;a-form-of-protest&quot;&gt;A form of protest&lt;/h2&gt;
&lt;p&gt;Ultimately, I agree with Salesforce’s decision to avoid the DTCG specification at this time. I’m a highly critical of the current direction. It is my opinion that it is scope-creeping into territories that will make it difficult for it to ever be finished.&lt;/p&gt;
&lt;p&gt;For example, the DTCG specification originally defined a color in this way:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    &amp;quot;colors&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;        &amp;quot;color-red-500&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;            &amp;quot;$type&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;color&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;            &amp;quot;$value&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;rgba(180, 216, 167, .75)&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the example, the &lt;code&gt;$value&lt;/code&gt; is a string. The newer specification is &lt;a href=&quot;https://github.com/design-tokens/community-group/pull/257&quot;&gt;in the process of defining color&lt;/a&gt; in this way:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    &amp;quot;Acid green&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;        &amp;quot;$type&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;color&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;        &amp;quot;$value&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;            &amp;quot;$hex&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;#00ff66&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;            &amp;quot;$colorSpace&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;                &amp;quot;name&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;srgb&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;                &amp;quot;$components&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;180&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 216&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 167&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;                &amp;quot;$alpha&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 0.75&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Among other critisms I have, seeing color defined in this way highlights why Salesforce finds “design tokens” too complicated for their customers. &lt;strong&gt;Defining all of the individual parts of a color in a structured object is tedious.&lt;/strong&gt; It is clear that the community group is less focused on making the file human-manageable at this point and expecting tools to help with the translation. I’m afraid this begins vendor lock-in where you might only be able to edit design tokens from tools. Salesforce Styling Hooks largely avoids the tooling needed to take the DTCG specification into their primary format for the web.&lt;/p&gt;
&lt;p&gt;I’ve spoken to Kaelig Deloumeau-Prigent, one of the co-chairs for the DTCG about the direction to this more complex object. The main reason seems to be the difficulty in parsing strings. His example explains that the CSS &lt;code&gt;rgb()&lt;/code&gt; color function is an example of the complexity because it takes several different kinds of syntax which any consuming application would need to support. Standarizing the format for systems to injest makes it easier. I contest that this makes it easier for the machines, not for the humans authoring tokens.&lt;/p&gt;
&lt;p&gt;I am biased in this area as the creator of &lt;a href=&quot;https://github.com/ddamato/token-operations&quot;&gt;Token Operations&lt;/a&gt;. While &lt;a href=&quot;https://github.com/ddamato/token-operations/issues/1&quot;&gt;folks could argue&lt;/a&gt; that the operations themselves are less accessible for human maintainers, the benefit is that those operations are for the machines but repeatable and sharable. The intention is for a single complex operation to be tucked away from human authors using those operations.&lt;/p&gt;
&lt;p&gt;I think a compromise in this area would be best. Where string concatenation could be added into the specification. Such that you could separate parts of the value meant to be concatenated for different platforms, but make it easier to author for humans. Based on my examples in &lt;a href=&quot;https://github.com/design-tokens/community-group/issues/224&quot;&gt;the DTCG issue&lt;/a&gt;, string concatenation would solve much of the problems that Token Operations would handle otherwise. This would allow for the original simplified construction while allowing for more complicated multi-platform values to exist. This would also finish the specification much faster by avoiding all of the complexities that might come from every individual &lt;code&gt;$type&lt;/code&gt;. Admittedly, this doesn’t solve for a zero-tooling ecosystem that Salesforce might have targetted, but I believe it would make it more accessible to those with minimal tooling.&lt;/p&gt;
&lt;h2 id=&quot;being-intentional&quot;&gt;Being intentional&lt;/h2&gt;
&lt;p&gt;Over the years, I’ve avoided the word “semantic token” to describe the middle tier due to &lt;a href=&quot;/posts/truly-semantic/&quot;&gt;my strict definition&lt;/a&gt; in favor of the word “&lt;a href=&quot;https://blog.damato.design/posts/tokens-as-intents/&quot;&gt;intent&lt;/a&gt;”. I continue to refer to this as a &lt;em&gt;type&lt;/em&gt; of design token to keep the concept connected. Where I work today, the word “design token” is rarely used in favor of “intents” which also delivers that strict definition. Where variables could be named and assigned anything, the criteria for similar as “intent” is more systematic and helps maintain a consistent construction and presentation as a result. No one asks “where are design tokens?” because &lt;em&gt;they are&lt;/em&gt; design tokens.&lt;/p&gt;
&lt;p&gt;It’s ok for design systems to be different, right? 😉&lt;/p&gt;</content:encoded></item><item><title>Avoiding z-index</title><link>https://blog.damato.design/posts/avoiding-z-index</link><guid isPermaLink="true">https://blog.damato.design/posts/avoiding-z-index</guid><pubDate>Fri, 13 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;From the days of working with design tools like Photoshop, layering compositions in 3D space on a computer has been part of the job. Managing what appears on top can be dozens of elements, maybe even groups of elements, and carefully curating the order of the layers is often a necessary unit of work.&lt;/p&gt;
&lt;p&gt;As you can expect, this sort of exercise has translated to the web, and traditionally we think the &lt;code&gt;z-index&lt;/code&gt; property is meant to manage this ordering in a similar way to how layers would work in a design tool. When you are working alone on your own project, this is reasonable because you are in control of the elements, the order, and the composition as a whole. You can decide if the &lt;code&gt;z-index&lt;/code&gt; you added yesterday isn’t good enough today and make modifications. You can tweak this part here, and make a small change there to get everything just right. In fact, I use &lt;code&gt;z-index&lt;/code&gt; right here on the blog in a few specific places to get things looking just right artistically.&lt;/p&gt;
&lt;p&gt;But for larger teams where elements are coming together from all across the organization to be composed into a single experience, trying to manage &lt;code&gt;z-index&lt;/code&gt; is a political battlefield. It’s not possible to just make a &lt;code&gt;--dropdown-elevation&lt;/code&gt; variable, because that dropdown might be on another surface that itself has an elevation higher than the dropdown.&lt;/p&gt;
&lt;p&gt;Popular public design systems like &lt;a href=&quot;https://polaris-react.shopify.com/tokens/z-index&quot;&gt;Shopify Polaris&lt;/a&gt; include &lt;code&gt;z-index&lt;/code&gt; tokens which don’t mention where the token is meant to be used, we just know they exist.&lt;/p&gt;
&lt;p&gt;There are certainly attempts at making sense of this. &lt;a href=&quot;https://css-tricks.com/the-value-of-z-index/&quot;&gt;A recent article on CSS-Tricks&lt;/a&gt; suggest naming the elements where they are expected to appear. Semantically, this makes sense on the surface. But as mentioned earlier, it’s very possible that a flyout that is normally underneath a modal is meant to later be on top of it. And it would be inappropriate to make an entirely separate component meant for “modal dropdowns”. Maybe it’s OK to set your own &lt;code&gt;z-index&lt;/code&gt;? Well, how do you know it isn’t conflicting with another element that will appear later in the lifecycle. You’re essentially playing whack-a-mole, goldilocking the perfect &lt;code&gt;z-index&lt;/code&gt; value, tokens or no tokens.&lt;/p&gt;
&lt;p&gt;But what if you didn’t need &lt;code&gt;z-index&lt;/code&gt; at all? There’s two approaches I want to highlight and both related to a very simple concept. &lt;strong&gt;Elements are visible in the order they appear in the DOM.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;top-layer&quot;&gt;Top layer&lt;/h2&gt;
&lt;p&gt;For what purpose do we set elements in 3D space on the web at all? Certainly, we can stylistically show something is a little bit raised for some personality but when we are creating flyouts and popovers, why are we using them. Overall, these are meant for focused attention. The user was currently navigating the general interface but needs to either focus on something further to continue. Sometimes that’s to choose an option, or maybe be notified of something. This means that there’s a hierarchy to what is being presented. This thing is currently important, then this thing is important, and so on. So this means as we introduce elements to the user, this is conveying a sense of importance. The most recent thing that is added, is the thing the user needs to see more than any other.&lt;/p&gt;
&lt;p&gt;This is how the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/Top_layer&quot;&gt;top layer&lt;/a&gt; works in HTML. It is a separate layer from the rest of the DOM where anything placed within it will be on top anything that would be placed in the normal DOM. No amount of &lt;code&gt;z-index&lt;/code&gt; can place elements higher than the top layer. Additionally, z-index doesn’t work in the top layer. So your question might be, how do I provide the correct order of elements? The order of the elements is how they are added to the top layer. That way, if you want some messaging to be the newly most important thing, you simply append it to the top layer.&lt;/p&gt;
&lt;p&gt;Elements that can apepar in the top layer are restricted to the following &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/Top_layer&quot;&gt;according to MDN&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fullscreen elements, i.e., elements that have been caused to display in fullscreen mode by a successful &lt;code&gt;Element.requestFullscreen()&lt;/code&gt; call.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt; elements displayed as a modal via a successful &lt;code&gt;HTMLDialogElement.showModal()&lt;/code&gt; call.&lt;/li&gt;
&lt;li&gt;Popover elements shown via a successful &lt;code&gt;HTMLElement.showPopover()&lt;/code&gt; call.&lt;/li&gt;
&lt;/ul&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;It seems you can also declaratively get popover elements into the top layer. There’s an &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/popover&quot;&gt;example at MDN&lt;/a&gt; using the &lt;code&gt;popover&lt;/code&gt; attribute which successfully renders into the top layer.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;Now, it’s more clear what is supposed to be on top. You can see all the elements and their visual order in devtools. Here’s an gif from the &lt;a href=&quot;https://developer.chrome.com/blog/what-is-the-top-layer&quot;&gt;Chrome for Developers article on the top layer&lt;/a&gt; showing how to inspect these elements.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/devtools-top-layer.gif&quot; alt=&quot;Devtools top layer inspection&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Devon Govett, one of the engineers behind Adobe Spectrum, &lt;a href=&quot;https://github.com/adobe/react-spectrum/discussions/9696#discussioncomment-15942257&quot;&gt;recently described some of the drawbacks&lt;/a&gt; about using the top layer. I’ve made a response to the comments about &lt;code&gt;&amp;lt;dialog/&amp;gt;&lt;/code&gt; in &lt;a href=&quot;https://www.youtube.com/watch?v=-blEWN_jM64&quot;&gt;a recent Wireframe episode&lt;/a&gt;. But it’s important to reiterate that you &lt;em&gt;do&lt;/em&gt; have control of the order, and I’d argue better control than spraying a new &lt;code&gt;z-index&lt;/code&gt; number and praying it doesn’t conflict with something else.&lt;/p&gt;
&lt;h2 id=&quot;grid-positioning&quot;&gt;Grid positioning&lt;/h2&gt;
&lt;p&gt;The other common reason why &lt;code&gt;z-index&lt;/code&gt; is used is to compositionally place elements on top of each other. This was very common when we used to use the &lt;a href=&quot;https://css-tricks.com/aspect-ratio-boxes/&quot;&gt;aspect ratio hack&lt;/a&gt; years ago for video. In this hack we’d need to use a padding value as a percentage which is based on the width of the element to maintain the aspect ratio of the box. Then we’d break the inner container out of the flow, and make it fill the parent’s dimensions.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.aspect-ratio-box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  height&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  overflow&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; hidden&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  padding-top&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(100&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; (16&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;9)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  position&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; relative&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-function)&quot;&gt;.aspect-ratio-box-inside&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  position&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; absolute&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  inset&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These days, if we needed a similar effect, we can just use &lt;code&gt;aspect-ratio: 16/9&lt;/code&gt; on the parent, but having a child fill a container is still important today. And it is commonly done using this combination of &lt;code&gt;position&lt;/code&gt; values.&lt;/p&gt;
&lt;p&gt;Using position creates a new &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Positioned_layout/Stacking_context&quot;&gt;stacking context&lt;/a&gt; which you probably don’t want and may have not even known was happening. While it might be harmless to use in one place, when you start positioning many shared elements, you might find putting a &lt;code&gt;z-index&lt;/code&gt; on one of them causes something else that was positioned to conflict. Understanding stacking contexts is very important when working with positioned elements, and there’s a &lt;a href=&quot;https://www.joshwcomeau.com/css/stacking-contexts/&quot;&gt;great article by Josh Comeau&lt;/a&gt; about them.&lt;/p&gt;
&lt;p&gt;But you can avoid creating a stacking context altogether using CSS grid! Assuming a similar HTML setup for the aspect ratio hack, here’s what that looks like with grid. I’ve removed the padding hack since we don’t need that any longer with modern CSS.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.aspect-ratio-box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  aspect-ratio&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 16/9&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  display&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; grid&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-function)&quot;&gt;.aspect-ratio-box-inside&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  grid-area&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1 / 1 / -1 / -1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;iframe height=&quot;500&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;Untitled&quot; src=&quot;https://codepen.io/fauxserious/embed/yyagwjq?default-tab=css%2Cresult&quot; frameborder=&quot;no&quot; loading=&quot;lazy&quot; allowtransparency=&quot;true&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/fauxserious/pen/yyagwjq&quot;&gt;
Untitled&lt;/a&gt; by Donnie D’Amato (&lt;a href=&quot;https://codepen.io/fauxserious&quot;&gt;@fauxserious&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;Any time you want to have an element match the dimensions of its parent, this is the technique that you should think of first. This approach avoids using &lt;code&gt;position&lt;/code&gt; and works with the order in which elements are provided.&lt;/p&gt;
&lt;p&gt;You can also place elements relative to the container. For example, maybe you’d like to place a close button at the top corner.&lt;/p&gt;
&lt;iframe height=&quot;500&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;Grid positioning banner&quot; src=&quot;https://codepen.io/fauxserious/embed/emdgXLx?default-tab=css%2Cresult&quot; frameborder=&quot;no&quot; loading=&quot;lazy&quot; allowtransparency=&quot;true&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/fauxserious/pen/emdgXLx&quot;&gt;
Grid positioning banner&lt;/a&gt; by Donnie D’Amato (&lt;a href=&quot;https://codepen.io/fauxserious&quot;&gt;@fauxserious&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 wouldn’t recommend this specific approach for handling a close button because &lt;a href=&quot;/posts/close-thy-enemy/&quot;&gt;the composition’s elements might conflict with each other&lt;/a&gt;. You should see the problem with this if you resize the example, heading will appear over the button. But it should give you some ideas of what else you might use CSS grid positioning for. Want the button on top, reorder the elements in the HTML.&lt;/p&gt;
&lt;p&gt;When we use and promote techniques that avoid pitfalls, we produce more robust applications and consistent systems of composition. Sure, CSS gives us a lot of tools, but it’s up to us to use them in thoughtful ways. Reaching for &lt;code&gt;z-index&lt;/code&gt; should be a last resort when everything else doesn’t work. There’s better ways in a modern web, we just need to take a moment while our chatbots are working to explore novel solutions on our own.&lt;/p&gt;</content:encoded></item><item><title>Beer goggles</title><link>https://blog.damato.design/posts/beer-goggles</link><guid isPermaLink="true">https://blog.damato.design/posts/beer-goggles</guid><pubDate>Mon, 19 May 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;Material Design 3 (Material You) was &lt;a href=&quot;https://m3.material.io/blog/announcing-material-you&quot;&gt;officially unveiled&lt;/a&gt; at Google I/O in May of 2021. At the time the new M3 site was still in the works with only a few analogs to the &lt;a href=&quot;https://m2.material.io/&quot;&gt;earlier Material Design site&lt;/a&gt;. I didn’t think much of this at the time, especially since 2021 was a busy year for me personally. But now, Material has a “new” launch called Expressive with &lt;a href=&quot;https://design.google/library/expressive-material-design-google-research&quot;&gt;an article explaining how we got here&lt;/a&gt;. The article triggers me for a few reasons:&lt;/p&gt;
&lt;h2 id=&quot;boredom&quot;&gt;Boredom&lt;/h2&gt;
&lt;p&gt;One of the first paragraphs in the article has the following quote:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Back in 2022, our research intern was studying user sentiment toward Material Design in Google apps. After mentioning her initial findings to colleagues in a Munich beer hall, she sparked a team-wide design debate: Why did all these apps look so similar? So boring? Wasn’t there room to dial up the feeling?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;One interpretation of this story is that you too can make a difference in a large organization with a small idea. Sounds very inspiring. However, when I read this, it looks like a group of designers were bored. There’s no user need spearheading the work. And this is something we see all the time. Some new designer comes in, looks at the current body of work for something they can own, and turns it into some project for a promotion. This occurs even if everything is working fine.&lt;/p&gt;
&lt;p&gt;Don’t get me wrong, there’s always things that can be improved, but it’s rarely the way that things look. It’s more often the way things work that need improvement. Unfortunately, it’s easier to put a new paint job on some walls than it is to teardown and rebuild parts of the house. A new coat of paint can really help make the room look new, but someone should really consider moving the toilet out of the kitchen.&lt;/p&gt;
&lt;h2 id=&quot;looksgood&quot;&gt;LooksGood™&lt;/h2&gt;
&lt;p&gt;Later in the article we get some “data”:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;These factors can be quantified in users’ responses to new M3 Expressive designs. We found a 32% increase in subculture perception, which indicates that expressive design makes a brand feel more relevant and “in-the-know.” We also saw a 34% boost in modernity, making a brand feel fresh and forward-thinking. On top of that, there was a 30% jump in rebelliousness, suggesting that expressive design positions a brand as bold, innovative, and willing to break from convention.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;These numbers are points describing the &lt;a href=&quot;https://lawsofux.com/aesthetic-usability-effect/&quot;&gt;Aesthetic-Usability Effect&lt;/a&gt;. Imagine conducting a survey and asking people about their feelings toward cotton candy versus a shovel. You’re going to get an overwhelming amount of positive responses for things that look fun and inviting over things that are designed to solve a user problem. If you then ask about the feelings between a pastel shovel and a brown shovel, you’ll probably get more people liking the pastel one because it looks unique and fun.&lt;/p&gt;
&lt;p&gt;The bottom line here is that we need things to be usable &lt;em&gt;first&lt;/em&gt;. We shouldn’t be triggering a redesign unless we need a hole and all we have is cotton candy.&lt;/p&gt;
&lt;h2 id=&quot;false-positives&quot;&gt;False positives&lt;/h2&gt;
&lt;p&gt;The next is an image from the article:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/expressive-email.png&quot; alt=&quot;Side-by-side of email application with design changes&quot;/&gt;&lt;/p&gt;
&lt;p&gt;The article claims that the participants were able to find the send button 4 times faster with the Expressive redesign specifically because of the following:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;By making the Send button larger and more prominent…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;However, I’d argue that the size and cosmetic treatment didn’t have the largest impact here. It certainly contributes, but the &lt;em&gt;placement&lt;/em&gt; change is more of a signficant factor. To demonstrate, consider if we were to imagine eye-tracking on writing an email. Your eyes should be following the words as you type, left-to-right moving downward. This means when you are finished, your eyes will be lower on the screen.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/expressive-email-eyes.png&quot; alt=&quot;Side-by-side of email application with design changes and eye path&quot;/&gt;&lt;/p&gt;
&lt;p&gt;This also means that the send button in the original application is in a suboptimal spot at the top-right corner. This isn’t just due to how we read, but items on the top edge are often overlooked in user interfaces as they are normally reserved for more generic items like user accounts or settings. The main action should be more prominently featured within the context of the user task.&lt;/p&gt;
&lt;p&gt;This is the difficulty with testing too many changes at once. You may wind up with a more usable solution but not know what of the changes was the definitive improvement. Changing the size, color, and placement of the button all at once can make it seem like the cosmetic changes were the qualities that provided the impact and falsy drive more resources into something that didn’t truly need it. Imagine painting your bedroom and realizing you have a lot of left over paint. So you decide to repaint all of the walls. They didn’t need to be repainted, you just did it because you were already motivated for that task. Meanwhile, the toilet is still in the kitchen.&lt;/p&gt;
&lt;h2 id=&quot;unfamiliarity&quot;&gt;Unfamiliarity&lt;/h2&gt;
&lt;p&gt;One final quote at the bottom of the article:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It is also worth noting that while expressive design improved preference and usability, it was impacted by users’ lack of familiarity. This is a challenge that designers will have to navigate, but we expect to see familiarity increase as more and more apps adopt this new style in the coming months.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This paragraph is justifying what happened during the hamburger menu explosion of 2016 and beyond. There’s plenty of articles showing both sides of the story across the internet &lt;a href=&quot;https://adactio.com/journal/10120&quot;&gt;ending up in a firm It Depends™&lt;/a&gt; from the community. When there’s so much debate, it’s easy to get lost in the opinions. The reality is that you want familiarity. This is &lt;a href=&quot;https://lawsofux.com/jakobs-law/&quot;&gt;Jakob’s Law&lt;/a&gt;. The more you make things unique and unfamiliar, the harder it will be for people to use.&lt;/p&gt;
&lt;p&gt;Take the new expressive email interface from before. I can’t tell you what all the other icon buttons next to the send button do. Why is it “image” and then “camera”? Can’t I see my images from the camera? Maybe the next one is a document scanner? Does the scanner write the document into my email or does it just attach like the paperclip used to do? I have no clue what the fourth icon is supposed to be. That last icon looks like a pen so maybe I can draw something in the email? All mostly unclear and unfamiliar.&lt;/p&gt;
&lt;h2 id=&quot;take-caution&quot;&gt;Take caution&lt;/h2&gt;
&lt;p&gt;The main point I’m making here is we’re seeing more designers going for low-hanging fruit of cosmetic changes instead of truly improving our experiences. I’m afraid that design teams are going to look at this “research” to justify their own exploration into expressiveness while neglecting better experiences for users. A technique like &lt;a href=&quot;https://mode.place/&quot;&gt;Mise en Mode&lt;/a&gt; can provide infinite amounts of expression. But at the end of the day, you still haven’t moved that toilet from the kitchen.&lt;/p&gt;</content:encoded></item><item><title>Big four oh</title><link>https://blog.damato.design/posts/big-four-oh</link><guid isPermaLink="true">https://blog.damato.design/posts/big-four-oh</guid><pubDate>Tue, 13 Dec 2022 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;It’s my birthday today, 40 times around the sun. I reflect back to the first time I started journaling; it was on my IBM computer in a text file I called “hyperjournal”. I really tried to be regular about it but just fell out of habit. Fast forward to now and it’s been 4 months since my last post but not for lack of effort.&lt;/p&gt;
&lt;h2 id=&quot;complementary-space&quot;&gt;Complementary Space&lt;/h2&gt;
&lt;p&gt;A topic that I’ve &lt;a href=&quot;/posts/spacing-solved&quot;&gt;written about on my blog&lt;/a&gt; and &lt;a href=&quot;https://www.youtube.com/watch?v=W2P-Bhbcj9k&quot;&gt;spoke about at a conference earlier this year&lt;/a&gt; is a new way to think of spacing tokens called &lt;a href=&quot;https://complementary.space/&quot;&gt;Complementary Space&lt;/a&gt;. It’s the follow-up to &lt;a href=&quot;https://gridless.design/&quot;&gt;Gridless Design&lt;/a&gt; which got a great deal of interest last year. Complementary Space has gotten a bit less attention but I think that’s understandable because it is experimental and not strictly design token based. It needs a different kind of mindset to fully embrace. Releasing it so close to the holidays was also probably bad timing. However, I appreciate all of the feedback I’ve received on it.&lt;/p&gt;
&lt;h2 id=&quot;connecting-with-community&quot;&gt;Connecting with community&lt;/h2&gt;
&lt;p&gt;So. many. design systems events. In the past few months I attended Schema and Clarity along with a dozen video conference events. The latest was &lt;a href=&quot;https://www.supernova.io/future-of-design-tokens&quot;&gt;a fully stacked panel speaking about the future of design tokens&lt;/a&gt; yesterday, and there’s &lt;a href=&quot;https://www.eventbrite.com/e/unconference-a-maturity-model-for-design-systems-registration-446204027257&quot;&gt;another event today&lt;/a&gt; (that I unfortunately must miss). I love how active this community is, where there is always a discussion to be had. I’m especially glad for the wrap up of yesterday’s panel where the leadership agreed that there’s a future where we &lt;em&gt;aren’t&lt;/em&gt; pushing pixels or making buttons because it’s already done. This gives us time to focus on what really matters; &lt;strong&gt;the experience&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;There is absolutely a world where design systems is not about the assets but about the infrastructure. I got an opportunity to catch up with &lt;a href=&quot;https://twitter.com/shaunbent&quot;&gt;Shaun Bent&lt;/a&gt; of Spotify who had &lt;a href=&quot;https://www.youtube.com/watch?v=Xww-x7DgiDw&quot;&gt;a talk&lt;/a&gt; a few years ago describing their onion model where a core system supports outer systems. This is where the future of design systems is for me; people who focus on the infrastructure of how resources are delivered across teams. We spoke a bit about the TV team for Spotify since it is especially niche and how the fit into the support strucuture. A question I had was “would it be more beneficial to have a representative of the TV team on the design system team?” Both of us don’t know what the answer to that is. There are pros and cons either way. For right now as I understand it, the TV team there is specialized and meets regularly with the design system team for alignment. Though I think these are questions we should be asking, not what is another way of displaying a token library.&lt;/p&gt;
&lt;p&gt;I absolutely love chatting with members of the design system community about these kinds of questions and topics.&lt;/p&gt;
&lt;h2 id=&quot;redesign&quot;&gt;Redesign&lt;/h2&gt;
&lt;p&gt;When I first launched this blog I didn’t put a lot of effort into the design because I expected folks to &lt;a href=&quot;https://blog.damato.design/feed.xml&quot;&gt;subscribe to the RSS feed&lt;/a&gt;. However, every time I’d look at this blog, I’d be so bored with the design of it. It wasn’t reflecting my personality and I wasn’t sure what direction to go. After playing around a bit and speaking with &lt;a href=&quot;https://jennifer.damato.design/&quot;&gt;Jen&lt;/a&gt; on this; she recommended that I lean harder into the hot takes and use &lt;a href=&quot;https://firstwefeast.com/tag/hot-ones&quot;&gt;Hot Ones&lt;/a&gt; as inspiration. I’m glad there’s another designer living with me to help get out of designers-block. 😅&lt;/p&gt;
&lt;p&gt;So now I rate each post with a &lt;code&gt;heat&lt;/code&gt; which will inform the accent color used on the post; from mild to volcanic. This isn’t visible at all in the feeds, but for those visiting the site it’ll be a nice bit of personality. Most of the colors being generated are accessible but I’m looking forward to the new color space functions in CSS to get further accessibility support. Jen also had the idea to have folks reading posts to influence the heat but I’m not about to hook this up to a custom database and authentication just for a single value.&lt;/p&gt;
&lt;p&gt;I’ve also updated the OG image generation to use &lt;a href=&quot;https://github.com/vercel/satori&quot;&gt;Satori&lt;/a&gt; by way of &lt;a href=&quot;https://www.npmjs.com/package/eleventy-plugin-og-image&quot;&gt;&lt;code&gt;eleventy-plugin-og-image&lt;/code&gt;&lt;/a&gt;, making it much easier to create images for each post. I hope there’s better support for CSS in the future with this tool but it does a good enough job for easy integration.&lt;/p&gt;
&lt;p&gt;I also want to put a bit of animation into the new neon synthwave effect for the titles but that’ll take a bit of time and exploration.&lt;/p&gt;
&lt;h2 id=&quot;plans-for-next-year&quot;&gt;Plans for next year&lt;/h2&gt;
&lt;p&gt;I have another large project that I started last year based on a short conversation with &lt;a href=&quot;https://danmall.com/&quot;&gt;Dan Mall&lt;/a&gt;. It’ll probably take a long time to officially announce since there’s a lot of work to be done for it. In the meantime I still expect to create posts here on a better cadence. I have over a dozen post ideas ready to be written.&lt;/p&gt;
&lt;p&gt;Additionally, I’m planning to put more focus on Mastodon and less in other social media platforms. I’m still not comfortable with the new platform because at the moment the circles are small. I hope more folks join for more connections to be made and that finding like interests is easier. However, it’s better than having notifications of suggested posts that are completely irrelevant to my interests like most other social platforms. So if you’re following me at the birdsite, I recommend you consider &lt;a href=&quot;https://www.wired.com/story/how-to-get-started-use-mastodon/&quot;&gt;coming over to Mastodon&lt;/a&gt; and &lt;a href=&quot;https://social.design.systems/@donnie&quot;&gt;following me there&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Looking forward to what the next 40 years may bring!&lt;/p&gt;</content:encoded></item><item><title>Book Authoring Backstage</title><link>https://blog.damato.design/posts/book-authoring-backstage</link><guid isPermaLink="true">https://blog.damato.design/posts/book-authoring-backstage</guid><pubDate>Wed, 25 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;By the time you are reading this, my several-year-long journey in book writing has neared its end. &lt;a href=&quot;https://mode.place&quot;&gt;My first book, Mise en Mode, is now available for purchase.&lt;/a&gt; Now that it’s complete, I wanted to document some of the process so that you might consider venturing out into the great unknown of self-publishing a little better than I did.&lt;/p&gt;
&lt;h2 id=&quot;how-it-started&quot;&gt;How it started&lt;/h2&gt;
&lt;p&gt;After &lt;a href=&quot;https://conffab.com/presentation/mise-en-mode/?gl=6qwtmtB93YWT&quot;&gt;speaking on the subject at Clarity in 2023&lt;/a&gt;, the topic generated a great deal of interest. I received lots of questions and people who wanted to know more. As per usual, I sat down and started writing another blog article here. But after looking at the reading time showing 15 minutes, not being anywhere near done, I felt it was time to go to the &lt;em&gt;next level&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I’ve always been interested in writing a book. I have a few books on writing books. Though I never had a topic that I felt passionate and knowledgeable enough to write about. I know they say that just because someone has written something before, there’s no reason not to write about it again, but I wanted to be unique with whatever my book was about. Mise en Mode was most certainly that opportunity.&lt;/p&gt;
&lt;h2 id=&quot;where-to-write&quot;&gt;Where to write&lt;/h2&gt;
&lt;p&gt;The next hurdle was &lt;em&gt;where&lt;/em&gt; I was supposed to put these words. I did some research here, and even spoke with Ethan Marcotte early on about his process. My big worry was, “if I start writing in X, will that make it easy to turn into a physical book?” The answer was one of the hardest parts of the process.&lt;/p&gt;
&lt;p&gt;I first started writing in &lt;a href=&quot;https://reedsy.com/&quot;&gt;reedsy&lt;/a&gt;. Its main selling point is that you will absolutely get a printed book using their platform. Additionally, it’s a web-based editor so I can write anywhere. I actually tried to use reedsy &lt;em&gt;twice&lt;/em&gt;, thinking that the shortcomings could be overlooked. The reality is that reedsy is not suited for technical books. It can’t support inline code and to speak about design tokens, there’s a lot of inline code. I figured if you’re writing something non-technical, this would be a good place to try.&lt;/p&gt;
&lt;p&gt;So from there, I searched for something that was more suited for technical writing. I saw some reddit posts that claimed the publishing houses might expect &lt;a href=&quot;https://asciidoc.org/&quot;&gt;AsciiDoc&lt;/a&gt; as a format because they already have templates to render that format into a book. From the look of the syntax it was markdown-like which was good. I preferred to write in markdown because I’ve been using it for years and it streamlines the content management process. I could also write and version control using GitHub so I could even edit in GitHub directly. The syntax isn’t really markdown, it’s a bit different but not too far from what I was used to writing.&lt;/p&gt;
&lt;p&gt;It’s been a while and I don’t remember the specifics but I ended up having problems rendering the final book using AsciiDoc. I know you need to install a few things in order to get it working, which I don’t really like. I think the biggest problem was customizing the final output to something that looked like a real book.&lt;/p&gt;
&lt;p&gt;That caused me to go out and look for other solutions. I’ll also say there’s a lot of red herrings out there. For example, the first line of &lt;a href=&quot;https://rust-lang.github.io/mdBook/&quot;&gt;mdbook&lt;/a&gt; says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;mdBook is a command line tool to create books with Markdown.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But when you read the next line, it’s clear this isn’t what I want:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It is ideal for creating product or API documentation, tutorials, course materials or anything that requires a clean, easily navigable and customizable presentation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It should be called mdDoc or mdWebpage.&lt;/p&gt;
&lt;p&gt;I eventually found &lt;a href=&quot;https://quarto.org/&quot;&gt;Quarto&lt;/a&gt; which has a syntax even closer to markdown. I even tried rendering what I had as a book and at first glance it seemed like everything worked well. I ended up writing the entire rest of the book in Quarto.&lt;/p&gt;
&lt;p&gt;Then, came the rendering.&lt;/p&gt;
&lt;p&gt;Even though I had sent a first pass through, it was where you look at the details. What I found was snag after snag. Quarto uses LaTeX and pandoc to render documents. LaTeX for the formatting, and pandoc to convert to a specified output. If you touch nothing, this works well enough. But if you need anything special, you are in for a challenge.&lt;/p&gt;
&lt;p&gt;One of the things that really caused me to throw out this toolchain was line wrapping. The token names in the book are long. For example &lt;code&gt;$action_primary_backgroundColor&lt;/code&gt; and because of this I expected the inline code to wrap when necessary. Otherwise, you’d get huge distracting gaps in the text. You might even be seeing this awful lack of wrapping in this very post! I’ll fix it here, eventually…&lt;/p&gt;
&lt;p&gt;However, for a printed book where I could curate how it looked precisely, this was unacceptable. However, no matter what I tried, I couldn’t get LaTeX to make these wrap. There were plenty of other problems like when to make pages break. I’d have code blocks and callouts broken between pages. I couldn’t believe how hard this was, or how this wasn’t just something built into the system. Why would it be acceptable for a code block that isn’t larger than a page to split between pages? I said to myself, I know exactly how to do this in CSS.&lt;/p&gt;
&lt;p&gt;One last attempt was to try and make this work using Adobe InDesign. My wife worked in publishing before and was familiar with the features of the program. However, what made this a non-starter was the restrictions on the callouts. Because the callouts are in their own colored boxes, they can’t be given styles like the normal paragraphs. My wife was trying to hack together something to make them look good enough, but at this point I didn’t want good enough. I wanted it to look like I expected it to look and I wanted it to be easy so if I needed to make an edit, it wouldn’t break the entire layout.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;At this point in the timeline, my book didn’t have an editor yet. I was shopping it around to different publishers, and when I did find a publisher I didn’t like that the rights were handed over. That’s why I ultimately chose to self-publish but also why it was important to have a process where I could make changes easily.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;h2 id=&quot;css-to-the-rescue&quot;&gt;CSS to the rescue&lt;/h2&gt;
&lt;p&gt;Toward the end of my frustrations with book layout, I couldn’t stop but think to myself “Why is this so hard? I could do this in CSS in minutes!” That’s when I went out to see if anyone actually did do this. That’s when I found &lt;a href=&quot;https://iangmcdowell.com/blog/posts/laying-out-a-book-with-css/&quot;&gt;this post by Ian McDowell&lt;/a&gt; where he outlines how he used CSS to layout his print book. He even shows the result at the end which was very inspiring.&lt;/p&gt;
&lt;p&gt;So, that’s exactly what I did. While I’m normally an &lt;a href=&quot;https://astro.build/&quot;&gt;Astro&lt;/a&gt; fanboy, I decided to use &lt;a href=&quot;https://www.11ty.dev/&quot;&gt;11ty&lt;/a&gt; for this because all I needed to do was convert markdown to HTML and 11ty is made for that. Then I could just write CSS as I normally would, hit &lt;code&gt;Ctrl+P&lt;/code&gt; on my keyboard and save it as a PDF. There’s actually not much more to it than that, but I’ll go over the items that are unusual.&lt;/p&gt;
&lt;p&gt;In my book I set up the following values:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;:root&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --page-size&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 6&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 9&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --page-margin&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; .75&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --inner-margin&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--page-margin) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1.5)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --runner-margin&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--page-margin) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 2)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;--page-size&lt;/code&gt; is used in the &lt;code&gt;@page&lt;/code&gt; declaration directly, along with the &lt;code&gt;--page-margin&lt;/code&gt; to go around each page:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-keyword)&quot;&gt;@page&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    size&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--page-size)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    margin&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--page-margin)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    counter-increment&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; page&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That counter increment property is described in &lt;a href=&quot;/posts/late-start/&quot;&gt;an earlier post that helps create page numbers&lt;/a&gt;. Next, we need to increase the inner margin on the correct pages.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-keyword)&quot;&gt;@page&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; :left&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    margin-right&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--inner-margin)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-color-text)&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;bottom-left-corner&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        font&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--font-caption)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        content&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; counter&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(page&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; false-start)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        margin-block-end&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--runner-margin)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;@page&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; :right&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    margin-left&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--inner-margin)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-color-text)&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;bottom-right-corner&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        font&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--font-caption)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        content&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; counter&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(page&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; false-start)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        margin-block-end&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--runner-margin)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The runner is the bottom of the page and this is a bit larger to make room for the page numbers. Finally a few other items to help with printing:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-string-expression)&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    -webkit-print-color-adjust&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; exact &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;!important&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    print-color-adjust&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; exact &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;!important&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/print-color-adjust&quot;&gt;&lt;code&gt;print-color-adjust: exact&lt;/code&gt;&lt;/a&gt; is used to tell the browser that these styles are made for print and to not make any opinionated changes to the page. Without it, the print rendering could look unexpected by removing background colors for example.&lt;/p&gt;
&lt;p&gt;From there, we have a few additional properties that help. For example, here’s all of the items that I want to avoid a page break:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;:where&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;ol&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; ul&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; table&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; figure&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; pre&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; blockquote&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;){&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    break-inside&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; avoid&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For headings, I have slightly different rule.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;:where&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; h2&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    break-before&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; right&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-function)&quot;&gt;:where&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;h3&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; h4&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    break-before&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; avoid&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For &lt;code&gt;h1&lt;/code&gt; (part titles) and &lt;code&gt;h2&lt;/code&gt; (chapter titles), I want to make sure that they always start on a right-hand page. That’s what &lt;code&gt;break-before: right&lt;/code&gt; is &lt;em&gt;supposed to do&lt;/em&gt; in theory. In practice, it doesn’t work because no browser has implemented it. Instead, I created a blank page element that I manually insert to get those pages in the correct place.&lt;/p&gt;
&lt;p&gt;For the &lt;code&gt;h3&lt;/code&gt; and &lt;code&gt;h4&lt;/code&gt; elements, I want to make sure that the following paragraph is connected to those headings. Otherwise, it would be weird if the heading was at the end of a page with its first paragraph on another page.&lt;/p&gt;
&lt;p&gt;There’s &lt;a href=&quot;https://www.smashingmagazine.com/2015/01/designing-for-print-with-css/&quot;&gt;a lot more to the CSS print specification&lt;/a&gt; that browsers haven’t implemented. &lt;a href=&quot;https://www.princexml.com/&quot;&gt;PrinceXML&lt;/a&gt; claims that its main feature is to implement these features and more. I looked into it after finishing the book, but it looks like it might be more involved than I was hoping. It wasn’t clear how to get it working after downloading the zip for me.&lt;/p&gt;
&lt;p&gt;But after that, I had a process to get a real ready-to-print PDF of my book. Next, is to make it real.&lt;/p&gt;
&lt;h2 id=&quot;publishing&quot;&gt;Publishing&lt;/h2&gt;
&lt;p&gt;I did a lot of research into self-publishing and ultimately went with &lt;a href=&quot;https://www.ingramspark.com/&quot;&gt;Ingram Spark&lt;/a&gt;. Most of the complaints were around customer service being slow, but the benefits of worldwide distribution and not being locked into a single Amazonian ecosystem was very enticing.&lt;/p&gt;
&lt;p&gt;Before this I bought ISBN numbers from &lt;a href=&quot;https://www.myidentifiers.com/&quot;&gt;Bowker&lt;/a&gt; because then you are able to have more flexibility than if a publisher gives you a free one.&lt;/p&gt;
&lt;p&gt;I’ll say that the process was mostly painless. There’s some tools at Ingram Spark that help you prepare your book. The cover template is a little tricky. For my hardcover it wasn’t clear how the template would be used. After getting the first book printed it was more clear that some of the lines were meant to indicate how the cover folds around the book.&lt;/p&gt;
&lt;p&gt;We originally made the cover in Adobe Illustrator but then cancelled our subscription because the cost was getting out of hand. Luckily &lt;a href=&quot;https://www.affinity.studio/&quot;&gt;Affinity&lt;/a&gt; is free and works just as well. There was a bit of a learning curve but we got the results we needed for the second round of printing. It was close enough such that when I submitted the cover design a third time with a small tweak, I was confident enough to enable the book to be sold without buying myself another copy.&lt;/p&gt;
&lt;p&gt;When you’re adding your book to your account, Ingram Spark asks you some questions about the purchase price. In this there’s areas where you need to set the wholesale discount. This is where I got tripped up. Basically, if someone buys your book direct from Ingram Spark, your cut is much higher than if they were to buy it from a middleman like Amazon. This means that it’s better for people to buy it direct from “you” (Ingram Spark). What they don’t tell you is that when Ingram Spark says they have the best distribution network, they mean to resellers, not themselves. I didn’t know this, so when I released my book, I found out it was only available to the US and UK directly through Ingram Spark.&lt;/p&gt;
&lt;h2 id=&quot;future&quot;&gt;Future&lt;/h2&gt;
&lt;p&gt;I’ve already started the process of getting the e-book available. It’s in review inside Ingram Spark and I’m planning to do a joint release making the e-book available at the same time that I enable worldwide distribution of the hardcover. I don’t know how long it’ll take for that to reach resellers but keep an eye out on my socials because I’ll be checking periodically and eventually updating the website with links that I get to the book.&lt;/p&gt;</content:encoded></item><item><title>Button size styles</title><link>https://blog.damato.design/posts/button-size-styles</link><guid isPermaLink="true">https://blog.damato.design/posts/button-size-styles</guid><pubDate>Wed, 10 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;This topic was sparked from a few &lt;a href=&quot;https://twitter.com/donniedamato/status/1778040346728964524&quot;&gt;discussions on Twitter&lt;/a&gt;. On one side there’s a school of thought that believes the size of a button should be achieved with padding. On the other side, there is also a belief that the size of the button should be handled with minimum dimensions. I have a strong opinion which is based on the principle that the size of an element is dictated by its contents and therefore I believe padding (along with other properties) should be the general basis for size.&lt;/p&gt;
&lt;h2 id=&quot;minimum-size&quot;&gt;Minimum size&lt;/h2&gt;
&lt;p&gt;If you are purely using &lt;code&gt;min-height&lt;/code&gt; to determine the size of the button, you aren’t accounting for the possibility of translations to your text. &lt;a href=&quot;https://gridless.design/for-designers#content-driven-design&quot;&gt;I’ve explained in the past&lt;/a&gt; that some words are translated to be much larger than initially provided. In that example, the words “Buy Now!” translated to Mongolian result in “Одоо худалдаж авах!”, something much longer than expected. In layouts with limited space, we will want to wrap the text for it to remain visible.&lt;/p&gt;
&lt;p&gt;In the following example, both buttons look similar in height, one using &lt;code&gt;min-height&lt;/code&gt; and the other using &lt;code&gt;padding-block&lt;/code&gt; (vertical padding).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/mongolian-button-oneline.png&quot; alt=&quot;Two buttons with lots of text&quot;/&gt;&lt;/p&gt;
&lt;p&gt;In this next example, we reduce the available space. If we purely use &lt;code&gt;min-height&lt;/code&gt; for the button to determine its dimension, we will lack space between the upper and lower edges of the button. Meanwhile, including padding in the button will ensure that there is always space from these edges; giving room for the text to breathe and not feel cramped.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/mongolian-button-twoline.png&quot; alt=&quot;Two buttons with lots of text, now breaking onto mulitple lines&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Note that in these examples, I’m not including space in the horizontal direction. I’d argue that we’d also want to use padding here as well.&lt;/p&gt;
&lt;h2 id=&quot;line-height-wont-save-you&quot;&gt;Line height won’t save you&lt;/h2&gt;
&lt;p&gt;Perhaps you have a personal vendetta against padding and want to do everything in your power not to use it. You say the &lt;code&gt;line-height&lt;/code&gt; will provide the additional vertical space I need! And yes, it might but at a cost. Here’s what that looks like using the first example, replacing &lt;code&gt;min-height&lt;/code&gt; with &lt;code&gt;line-height&lt;/code&gt; to get a similar size with padding.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/mongolian-button-lh1.png&quot; alt=&quot;Two buttons with lots of text&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Now, here’s what happens when the text breaks onto two lines.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/mongolian-button-lh2.png&quot; alt=&quot;Two buttons with lots of text&quot;/&gt;&lt;/p&gt;
&lt;p&gt;You’ll see that the &lt;code&gt;line-height&lt;/code&gt; causes too much space to appear between the lines in the first button. This is expected because that’s the purpose of &lt;code&gt;line-height&lt;/code&gt;; it’s meant to control the height of each line. While we don’t expect a button to wrap to multiple lines and cause this wide gap to appear, we should still be prepared for it.&lt;/p&gt;
&lt;p&gt;Also, know that the resolved &lt;code&gt;line-height&lt;/code&gt; value will be presented differently between different fonts and their metrics. I love recommending &lt;a href=&quot;https://iamvdo.me/en/blog/css-font-metrics-line-height-and-vertical-align&quot;&gt;this post by Vincent De Oliveira&lt;/a&gt; to deep-dive into the differences. So if you &lt;em&gt;don’t&lt;/em&gt; want the size to be related to the font, then &lt;code&gt;line-height&lt;/code&gt; isn’t your tool.&lt;/p&gt;
&lt;p&gt;Set the &lt;code&gt;line-height&lt;/code&gt; value based on what you’d like to see when the content wraps to multiple lines. This goes for &lt;em&gt;any&lt;/em&gt; prose, not just the button. You should not be setting a &lt;code&gt;line-height&lt;/code&gt; value when looking at only a single line of text.&lt;/p&gt;
&lt;h2 id=&quot;why-not-use-both&quot;&gt;Why not use both?&lt;/h2&gt;
&lt;p&gt;Because it’s redundant.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;padding&lt;/code&gt; contributes to the height of the component (along with the &lt;code&gt;line-height&lt;/code&gt;). So as long as there is content inside the button, the button will be the same height related to the content within it. &lt;code&gt;min-height&lt;/code&gt; is only useful if we expect the button to not have any content within it and that should never happen. If it does happen, you have larger problems than the height of the button.&lt;/p&gt;
&lt;h2 id=&quot;mixed-content&quot;&gt;Mixed content&lt;/h2&gt;
&lt;p&gt;Now, I’m sure you are already thinking of an exception where there is mixed content in the button; specifically an icon with text and those elements do not share the same height.&lt;/p&gt;
&lt;p&gt;There’s a great deal of nuance in this area, but the bottom line is that you want the space that the icon occupies to match the &lt;code&gt;line-height&lt;/code&gt; of the font it is paired with. This may mean that you’ll include a negative &lt;code&gt;margin-block&lt;/code&gt; using a unit related to the current font metrics to get the appropriate optical placement without adding to the overall size.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/adobe-icon-buttons.png&quot; alt=&quot;Adobe icon buttons with text&quot;/&gt;&lt;/p&gt;
&lt;p&gt;In the above example showing &lt;a href=&quot;https://spectrum.adobe.com/page/button/#Size&quot;&gt;buttons from Adobe Spectrum&lt;/a&gt;, placing the icon on the font’s baseline would not vertically center the glyph. We must offset this at the icon. Here’s an example of a few approaches, all with the &lt;code&gt;padding-block&lt;/code&gt; property set.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/button-icon-compare.png&quot; alt=&quot;Several button examples with alignment&quot;/&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Button with no icon.&lt;/li&gt;
&lt;li&gt;Button with icon using negative margin related to the font metrics.&lt;/li&gt;
&lt;li&gt;Button with icon using &lt;code&gt;vertical-align&lt;/code&gt; related to the font metrics.&lt;/li&gt;
&lt;li&gt;Button with icon without alignment adjustments.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In the second and third examples, the icon is optically centered with the text. The difference is how much the icon contributes to the button height. In the third example using &lt;code&gt;vertical-align&lt;/code&gt;, the height still contributes to the overall size, causing the button to be much larger when an icon is provided, even while centered with the text.&lt;/p&gt;
&lt;p&gt;Using the negative margin with the correct value can also be used when text does not appear within the button. Here’s the same example as above, now with an icon-only button which also uses the negative margin value.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/button-icon-only.png&quot; alt=&quot;Several button examples with alignment&quot;/&gt;&lt;/p&gt;
&lt;p&gt;I’d suggest that your icon component should be built in with a negative margin based on the current font metrics. Getting the font metrics to behave isn’t easy but &lt;a href=&quot;https://caniuse.com/css-text-box-trim&quot;&gt;some CSS properties are coming that might be useful&lt;/a&gt;. This is especially critical in a themed ecosystem as the resulting value for the negative margin will change depending on the font properties for any given theme.&lt;/p&gt;
&lt;h2 id=&quot;thoughtful-units&quot;&gt;Thoughtful units&lt;/h2&gt;
&lt;p&gt;Here’s one final hot take, and it happens to be an argument against what I’ve previously thought in the past. Consider &lt;em&gt;not&lt;/em&gt; using &lt;code&gt;(r)em&lt;/code&gt; for size/space. 😱&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.joshwcomeau.com/css/surprising-truth-about-pixels-and-accessibility/#strategic-unit-deployment-6&quot;&gt;Josh Comeau has an excellent demo of this in his post.&lt;/a&gt; The reason why we apply space to anything is often meant to show relationships between elements. In the case of the button, we are applying space for an additional reason; to increase the size of the target for better clickability.&lt;/p&gt;
&lt;p&gt;If the font size were to increase due to the user’s zoom, the target area would become larger as a result when the content dictates the size of the element. We do not need to &lt;em&gt;also&lt;/em&gt; increase the space surrounding the button; the resulting content size is enough to click. In this way, the padding is effectively contributing to the minimum height of the button.&lt;/p&gt;
&lt;p&gt;In the other direction, if the user wants to &lt;em&gt;decrease&lt;/em&gt; the text size, using a padding size that ensures a proper target area is available is recommended. Decreasing the text size is less common than increasing but could occur in areas where data is meant to be dense, like in a table to view more information.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you want the size/space to be affected by the relative font size, use &lt;code&gt;em&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If you want the size/space to be affected by the user’s font size preference, use &lt;code&gt;rem&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If you want the size/space to remain the same regardless of these settings, use &lt;code&gt;px&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I’d now argue that the final one is more appropriate than we might realize when it comes to relationships and user settings. The user is generally increasing their font size for legibility and has very little to do with increasing visible space between elements. Meanwhile, the user still has the option to zoom, which causes everything to be larger for nearly any unit being used.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/62-5&quot;&gt;It is still important to use relative units for typography.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We should be deliberate in the reason why we choose to make these design decisions and keep in mind that we have very little control over how a user might want to experience the stuff we make.&lt;/p&gt;</content:encoded></item><item><title>Button width styles</title><link>https://blog.damato.design/posts/button-width-styles</link><guid isPermaLink="true">https://blog.damato.design/posts/button-width-styles</guid><pubDate>Fri, 05 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;My wife asked me a question one morning:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Are there any good reasons why a button should have a min-width?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;My quick response was “No” and she agreed without much contest. However, I figured &lt;a href=&quot;https://x.com/donniedamato/status/1802756674047873288&quot;&gt;I’d ask the internet&lt;/a&gt; to see if there were any reasons we might have missed.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;While I’ll use the term “width” for much of this article, I recognize that some languages would be displayed in a vertical &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/writing-mode&quot;&gt;writing-mode&lt;/a&gt;. You can assume that when we mention width, we are referring to the inline axis in CSS which could be replaced with &lt;code&gt;inline-size&lt;/code&gt;.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;Moving forward, we assume that the button we are designing is the smallest possible in any particular set, as larger buttons will be less susceptible to the issues we’ll be addressing.&lt;/p&gt;
&lt;h2 id=&quot;accessibility&quot;&gt;Accessibility&lt;/h2&gt;
&lt;p&gt;One of the big blanket statements in the replies was related to accessibility. Specifically citing &lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/target-size-minimum.html&quot;&gt;WCAG 2.5.8 AA&lt;/a&gt; which says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Undersized targets (those less than 24 by 24 CSS pixels) are positioned so that if a 24 CSS pixel diameter circle is centered on the bounding box of each, the circles do not intersect another target or the circle for another undersized target.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It’s important to note that 24 CSS pixels is a minimum and the better practice is to have target areas that meet the &lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/target-size.html&quot;&gt;WCAG 2.5.5 AAA&lt;/a&gt; of 44 CSS pixels.&lt;/p&gt;
&lt;p&gt;There are plenty of situations that we could imagine where a larger target would be helpful:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For folks using a device in a moving vehicle.&lt;/li&gt;
&lt;li&gt;For folks who use less accurate pointing devices.&lt;/li&gt;
&lt;li&gt;For folks that lack fine motor skills.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My stance on this is that button construction will contribute to the overall accessible size using styles like padding and the existing content to meet this without much more to add. Additionally, buttons with words inside should have the proper content that is descriptive and avoid vague labels like “OK.” More on this below.&lt;/p&gt;
&lt;h2 id=&quot;localizaton&quot;&gt;Localizaton&lt;/h2&gt;
&lt;p&gt;Having a more descriptive label doesn’t necessarily mean that buttons with only two characters won’t exist. According to &lt;a href=&quot;https://x.com/mikemai2awesome/status/1802873782169633032&quot;&gt;Mike Mai&lt;/a&gt;, it’s common for pages that display &lt;a href=&quot;https://en.wikipedia.org/wiki/CJK_characters&quot;&gt;CJK languages&lt;/a&gt; to have a button with only two characters.&lt;/p&gt;
&lt;p&gt;Meanwhile for languages that would cause the button to be larger than originally designed due to translation, a minimum width would be easily exceeded. In &lt;a href=&quot;https://gridless.design/&quot;&gt;an example I’ve used before&lt;/a&gt;, the words “Buy Now!” translated to Mongolian results in the text “Одоо худалдаж авах!” overshooting any reasonable &lt;code&gt;min-width&lt;/code&gt; that might have been applied. The &lt;code&gt;min-width&lt;/code&gt; is intended for when the label is too small, not when it is large.&lt;/p&gt;
&lt;p&gt;Speaking of when a button has a long label, we &lt;strong&gt;should not truncate&lt;/strong&gt; the text in favor of an ideally sized button. We must curate the label in such a way that it is descriptive and concise. If the text must wrap, let the text wrap and continue to be wholly visible. &lt;a href=&quot;/posts/button-size-styles&quot;&gt;I’ve written a bit more on this topic recently.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;icon-button&quot;&gt;Icon button&lt;/h2&gt;
&lt;p&gt;It is also not uncommon to have a single glyph within a button in the form of a square icon button. If the button is meant to be a square, then its width and height should match by definition. Since we’d most likely want a standardized height for buttons so they align with inputs and other text elements, the width would be naturally restricted to this recurring height.&lt;/p&gt;
&lt;p&gt;Therefore, the smallest button in the library should be the square icon button which must meet WCAG 2.5.8 AA as defined earlier; a minimum of 24 CSS pixels in both dimensions. No minimum width would be apparent when set in this configuration using only an icon. The minimum width of the icon button would be the size of the icon plus any additional padding and borders, adding up to at least 24 CSS pixels but optimally 44 CSS pixels.&lt;/p&gt;
&lt;h2 id=&quot;looksgood&quot;&gt;LooksGood™&lt;/h2&gt;
&lt;p&gt;There are plenty of responses that provide the opinion that setting the &lt;code&gt;min-width&lt;/code&gt; will make buttons with smaller labels visually more appealing than without. Such as if there were two buttons labeled “Yes” and “No”, the designer might expect the width of both buttons to match in size. There isn’t any data from a usability perspective that I could find that supports this design choice as beneficial. It is a matter of subjective design preference. I also believe that better content design would make this unnecessary. The need for a &lt;code&gt;min-width&lt;/code&gt; presupposes that the content in the offending button could be improved with a more descriptive label.&lt;/p&gt;
&lt;h2 id=&quot;other-points&quot;&gt;Other points&lt;/h2&gt;
&lt;p&gt;There was a point that listed predictability, consistency, and readability as factors that would involve setting a &lt;code&gt;min-width&lt;/code&gt;. In the cases of predictability and consistency, the visual treatment of the button using color, typography, and other styles would contribute more to these factors than the width. I’d even argue that a &lt;code&gt;min-width&lt;/code&gt; button would be &lt;em&gt;less&lt;/em&gt; visually consistent than one without because of the horizontal padding. A “Yes” button with a &lt;code&gt;min-width&lt;/code&gt; set would be perceived as having more padding than buttons that don’t reach the &lt;code&gt;min-width&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/button-min-width.png&quot; alt=&quot;Yes, No, and Send Email buttons with the same minimum width&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Meanwhile, if all buttons were perceived to have identical padding, this would be a more consistent visual treatment. In the case of readability, this is determined by font metrics, icon design, and color contrast, not the width of the containing element.&lt;/p&gt;
&lt;p&gt;Another point shared was about buttons in spatial computing. Admittedly, I’m not well-versed in these interfaces so I asked some questions about the interaction design for these. According to the thread, these buttons will grow as you gaze at them with your eyes, indicating that a particular button is an intended target. The button is commonly triggered using a pinch but could also be by finger touch, which aligns with earlier recommendations discussed above. I’d also imagine that visually small buttons could be made larger by changing one’s perspective similar to how browser zoom controls would work, but without the layout shifts.&lt;/p&gt;
&lt;h2 id=&quot;the-only-reason&quot;&gt;The only reason&lt;/h2&gt;
&lt;p&gt;So if we were to assume that the button is designed in good faith, with appropriate padding and borders, using legible font metrics and color contrast, and having either a well-identified icon or descriptive label, that this button would not need a &lt;code&gt;min-width&lt;/code&gt; to be set.&lt;/p&gt;
&lt;p&gt;However, there is one reason why we might want to consider setting a &lt;code&gt;min-width&lt;/code&gt; and it has to do with CSS Flexbox. Kevin Powell has made &lt;a href=&quot;https://www.youtube.com/watch?v=FD3aC_Ke8uk&quot;&gt;a great explainer video speaking about the behavior&lt;/a&gt; so I recommend watching it for more information. The tl;dr is that because most buttons these days are designed using Flexbox, then I’d recommend including the following rule with the declaration to help with text wrapping when it’s needed:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    min-width&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Without it, it’s possible that text within the Flexbox could overflow outside the shape as an unintended consequence of responsive behavior and translation. It’s important for the content to flow naturally, and setting this rule when using Flexbox helps support that expectation.&lt;/p&gt;
&lt;p&gt;So from a design perspective, I’m not convinced that setting a minimum width for the button has a reason for usability as long as other aspects of the button are well designed. From the engineering perspective, setting &lt;code&gt;min-width: 0;&lt;/code&gt; on the item will help support content wrapping.&lt;/p&gt;</content:encoded></item><item><title>Chip Away</title><link>https://blog.damato.design/posts/chip-away</link><guid isPermaLink="true">https://blog.damato.design/posts/chip-away</guid><pubDate>Mon, 23 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;One of the most confusing but ubiquitous patterns in design is “small text with a background color that may or may not be interactive”. To some that sounds like a button with an identity crisis but to others they might recognize this as a few names: chip, badge, pill, tag, or even &lt;a href=&quot;https://atlassian.design/components/lozenge/&quot;&gt;lozenge&lt;/a&gt;. It’s bad enough that the definition of these things is contested, but what is worse is because they are all generally so visually similar, it makes it hard for the &lt;em&gt;users&lt;/em&gt; to know what they are meant to do.&lt;/p&gt;
&lt;h2 id=&quot;lets-play-a-game&quot;&gt;Let’s play a game&lt;/h2&gt;
&lt;p&gt;As a little exercise, all of these are from the same design system. Try to guess what the name of each of them is:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/what-component.png&quot; alt=&quot;Different named components that look the same&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Before I reveal the answers, just think about my earlier definition of these things. They all match the description. Remember that users aren’t discerning the small idiosyncrasies between them, they are most likely lumping all of these into the same category “small text with background color”.&lt;/p&gt;
&lt;p&gt;Ok, next exercise. Here’s the definition of each of these components:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A visual indicator used to communicate status.&lt;/li&gt;
&lt;li&gt;A compact label used to classify, organize, and categorize information.&lt;/li&gt;
&lt;li&gt;Used to display numeric status data.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The definitions here might give you a hint about which of these components they are assigned but &lt;em&gt;only&lt;/em&gt; because of the content found in the examples. Again, think about what is more likely happening. A designer is probably thinking I need “small text with background color” and every one of these satisfies that criteria. How often do we find designers justifying which one of these things they are meant to use? I’d argue it’s more common to have a preconceived notion of the visual design without thinking &lt;em&gt;why&lt;/em&gt; they are choosing that approach. It’s usually gets reduced to “I’ve seen it before” or “this other big company does it” without much of a conversation to justify the decision. We’re encoding a few whys as definitions to justify different components, but in the end we often miss how that why is helping our designers or our users.&lt;/p&gt;
&lt;p&gt;The answers are below:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://atlassian.design/components/badge&quot;&gt;Badge&lt;/a&gt; is a visual indicator for numeric values such as tallies and scores.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://atlassian.design/components/lozenge&quot;&gt;Lozenge&lt;/a&gt; is a visual indicator used to highlight an item’s status for quick recognition.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://atlassian.design/components/tag&quot;&gt;Tag&lt;/a&gt; is a compact label used to classify, organize, and categorize information.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;filters-and-categorization&quot;&gt;Filters and categorization&lt;/h2&gt;
&lt;p&gt;The following examples are from &lt;a href=&quot;https://uxcel.com/&quot;&gt;Uxcel&lt;/a&gt;, specifically &lt;a href=&quot;https://app.uxcel.com/lessons/anatomy-694&quot;&gt;their page on “UI Chips”&lt;/a&gt;. Take a close look and try to figure out the difference:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/what-difference.png&quot; alt=&quot;A do and don&apos;t image that look very similar&quot;/&gt;&lt;/p&gt;
&lt;p&gt;These are the first images of their explainer where one of these is described as a “do” and the other as a “don’t”. At a glance, it’s very hard to tell which the do and don’t is. Here’s the text from their explainer:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You might wonder how chips differ from buttons. They can look similar, but they work differently. Chips, especially when used as filters, help users narrow down or adjust what they see without leaving the current view…&lt;/p&gt;
&lt;p&gt;Buttons, on the other hand, are for clear, single-purpose actions like “Save,” “Submit,” or “Cancel.” They’re used when the user needs to make a decision or move to the next step.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But isn’t filtering an &lt;em&gt;action&lt;/em&gt;? To filter is a verb, therefore an action. And each of these chips is filtering meant for a single-purpose, to filter the entities represented by the label. Buttons aren’t meant to leave the current view either, they are meant to execute an action.&lt;/p&gt;
&lt;p&gt;It’s very easy to pick the definition apart to show that there’s not much difference happening here, not just visually but also behavior. The only difference that I could glean from these is that the labels on the chips are nouns, representing the entities that will be affected once you tap the button. Meanwhile, the buttons have verbs telling you what will happen. For buttons, this is good practice. The label is describing an action, and a user reading that label can assume interacting with this element will perform the action on the label.&lt;/p&gt;
&lt;p&gt;But the chips example is very ambiguous. Again, users don’t care how you classify this thing as a button or a chip. They are trying to figure out how it is going to help them. So, they’ll look at the chips example and potentially wonder what the “Vegetarian Button” does. Some folks will tap it, some won’t because it’s not clear. Now, let’s see an alternative:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/checkbox-filters.png&quot; alt=&quot;Checkbox filter pattern&quot;/&gt;&lt;/p&gt;
&lt;p&gt;I know what you’re going say: “Donnie, that’s too much text!” In comparison to the original, absolutely. However, you can’t argue that this approach is more clear about how I’m meant to interact with this UI, and what the result will be. If the amount of text on each label is truly bothering, consider a hybrid approach:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/checkbox-legend.png&quot; alt=&quot;Checkbox filter with legend pattern&quot;/&gt;&lt;/p&gt;
&lt;p&gt;But hold on, are those chips in the original comparison image &lt;em&gt;actually&lt;/em&gt; filters? Take another look, because these things &lt;em&gt;could&lt;/em&gt; simply be describing the attributes of the location, and not actually do anything if you tap them. If that’s the case, then the image barely matches their description of a chip! If these chips aren’t filters, then it’s just a stylized list.&lt;/p&gt;
&lt;h2 id=&quot;schrödingers-button&quot;&gt;Schrödinger’s button&lt;/h2&gt;
&lt;p&gt;This is ultimately the largest problem with this pattern. It is very often a guessing game to figure out if this thing is interactive. Take a look at this example and ask yourself, can I click the element that says “Pro”?&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/can-i-click.png&quot; alt=&quot;User info lockup&quot;/&gt;&lt;/p&gt;
&lt;p&gt;The answer is 🤷, it’s Schrödinger’s button. You only know if you can interact with it until you do. Until then you are left guessing about if you can. You might think, what is the harm of tapping the button to find out? You might be surprised in &lt;a href=&quot;https://link.springer.com/chapter/10.1007/978-3-031-59080-1_10&quot;&gt;research&lt;/a&gt; that shows a type of &lt;a href=&quot;https://en.wikipedia.org/wiki/Koumpounophobia&quot;&gt;koumpounophobia&lt;/a&gt;; a fear of buttons:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;…older adults had many negative emotional user experiences, including fear of pressing buttons and embarrassment of incompetence.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So, it is possible that your user won’t even try and never discover something that you felt was useful because they don’t know what “Pro” does. Does it work like a checkbox and revoke the “Pro” status for this person? Does it tell me what a “Pro” is? Does it tell me &lt;em&gt;why&lt;/em&gt; this person is a “Pro”? The fact is, this element is probably not interactive. So, don’t make it look interactive.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/pro-profile.png&quot; alt=&quot;Pro is within avatar&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Or if it is interactive, tell me what it will do. Make it a verb. Be deliberate in this decision. And of course, make it look like a proper button.&lt;/p&gt;
&lt;p&gt;You should also ask, does this need to be in the interface at all? Is it important that a person know this is a pro user? Ask yourself what is that importance. It’s true that &lt;a href=&quot;https://www.sciencedirect.com/science/article/abs/pii/S1567422319300110&quot;&gt;social comparison is a motivating factor&lt;/a&gt; and seeing someone with a physical conference badge walking around your city can have a fleeting thought “I wonder what they are showing at that conference?” So, having a digital badge on your profile, like a verified badge has a similar effect. If that’s the case, consider using other treatments that show status that are clearly not interactive, such as typographic hierarchy to show importance.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/pro-member-hierarchy.png&quot; alt=&quot;Pro member using typographic hierarchy&quot;/&gt;&lt;/p&gt;
&lt;p&gt;In this example Cally is both a “Pro Member” and a “Photographer”. We display a slight difference between the status that was given to user from the status that was chosen by the user. If icons are well understood within the product’s ecosystem, you can consider adding an icon to further highlight the status.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;Icons also have the possibility of suggesting interactivity. If you’re going to use an icon to direct the user’s attention to this status, it should be a well-established pattern first. The icon used here should already be prominently used to indicate the status in other patterns. Otherwise, it might have the same effect as “small text with a background color that may or may not be interactive” even without the background.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;h2 id=&quot;tag-inputs&quot;&gt;Tag inputs&lt;/h2&gt;
&lt;p&gt;Sometimes, this element is used in combination with a text field. The tag input is a pattern where you have an input field that allows you to enter text, and when you hit a special key (like a comma), it creates an entity with the text you entered. The benefit of this pattern is that a user can create several entities on the fly. Otherwise, the user would need to create an entity, give it a label, and save it for each piece of information they want to enter. With a tag input, they can just keep entering text and creating new entities without having to go through the process of creating and saving each one individually.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/tag-input.png&quot; alt=&quot;YouTube tag input&quot;/&gt;&lt;/p&gt;
&lt;p&gt;The challenge with this pattern is accessibility. When keyboard navigating to each chip, how does it focus? At first you’d expect to focus the entire chip, but then the next tabbable element would be the “x” button inside the chip. This means that technically we have an interactive element inside of another interactive element, which is an accessibility violation. This also requires someone to tab twice to move to the next tag.&lt;/p&gt;
&lt;p&gt;The more appropriate approach is to make the tag a non-interactive element, and only make the “x” button interactive. This way, when you tab to the next tag, it will focus the “x” button, and you can press it to delete the tag if you want. This also means that you can easily move to the next tag without having to tab twice. Think about it, why would you want a person to focus a newly created tag if the only thing they can do with it is delete it? It doesn’t make sense to have a person focus something that they can’t interact with, and then require them to tab again to interact with it. It’s much more efficient to just focus the interactive element directly.&lt;/p&gt;
&lt;p&gt;Another note about accessibility for this pattern is that when you create a new tag, you should announce it to screen readers. This can be done using an ARIA live region, which will allow screen readers to announce the new tag as soon as it’s created. This way, users who rely on screen readers will be aware of the new tag and can interact with it if they choose to.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; aria-live&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;polite&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; aria-atomic&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;sr-only&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;announcer&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then when a new tag is created, you can update the content of the live region:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;announcer&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.textContent &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; `Tag added: &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;. Press Backspace to remove.`&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While it is common to visually put instructions on how to use the tag input below the input field, it would be better to show this information &lt;em&gt;above&lt;/em&gt; the field. This goes for any input field, but especially for fields that have uncommon behavior, such as eating commas to create tags. Imagine how confusing it would be to have an empty canvas and not know what you’re supposed to be doing with it until later. Having instructions upfront prepare the user for what is about to come.&lt;/p&gt;
&lt;p&gt;Don’t forget that users can also dictate in accessible technologies, and depending on the user’s settings, commas may be inserted automatically instead of deliberately. It is possible that for some users, speaking the word comma will enter the literal word “comma” instead of the punctuation. This is something to consider when designing the interaction for this pattern, as it may not be intuitive for all users. There’s also no reliable way to know if the user is dictating, as this is often supplied by the operating system. This also doesn’t account for an &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/Input_method_editor&quot;&gt;Input Method Editor (IME)&lt;/a&gt; for non-Latin languages, which may have their own unique behaviors when it comes to punctuation and special characters. It’s important to consider these edge cases when designing the interaction for a tag input, and to provide clear instructions for all users on how to use the feature effectively.&lt;/p&gt;
&lt;p&gt;Unless, you simplify by using a pattern that nearly every developer has built as their first project:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/todo-app.png&quot; alt=&quot;Todo App&quot;/&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No delimiter parsing&lt;/li&gt;
&lt;li&gt;No dependence on comma&lt;/li&gt;
&lt;li&gt;No IME conflicts&lt;/li&gt;
&lt;li&gt;No dictation ambiguity&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is a much more straightforward approach, and it still allows users to create multiple tags on the fly without having to go through the process of creating and saving each one individually. It’s also more accessible for users who may have difficulty with the original pattern, as it doesn’t rely on specific key presses or punctuation to create new tags. Overall, it’s a simpler and more inclusive design choice for a tag input feature.&lt;/p&gt;
&lt;h2 id=&quot;a-hard-pill&quot;&gt;A hard pill&lt;/h2&gt;
&lt;p&gt;While this post seems to be stripping all of the fun out of user interface design, the intention is to encourage designers to be more deliberate in their choices. To stop and think about how people outside of their tech circle might use this product. If you are going to use a pattern that has ambiguity, make sure you are doing it for a good reason. If you are using “small text with a background color that may or may not be interactive” just because it looks nice, then you might be alienating users; &lt;em&gt;users who want to pay for your product&lt;/em&gt;. It’s important to remember that design is not just about aesthetics, but also about usability and accessibility. By being more intentional in our design choices, we can create interfaces that are not only visually appealing but also easy to use and understand for all users.&lt;/p&gt;</content:encoded></item><item><title>Choose wisely</title><link>https://blog.damato.design/posts/choose-wisely</link><guid isPermaLink="true">https://blog.damato.design/posts/choose-wisely</guid><pubDate>Mon, 15 Aug 2022 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;If you believe in free-will, options are most likely a foundational aspect of your philosophy. Designers are responsible for presenting choices to users so that they may select the best option and advance toward a goal. Historically, we have introduced several patterns which support the ability for users to make a choice. In this exploration we will consider some common interface components and understand why we might decide to use one over another.&lt;/p&gt;
&lt;h2 id=&quot;ground-rules&quot;&gt;Ground rules&lt;/h2&gt;
&lt;p&gt;The abstract concept we’ll be focusing on is a group of similar items and the ways they can be presented and interacted. This means singular buttons and inline links aren’t included in this exploration.&lt;/p&gt;
&lt;p&gt;The act of creating an option will also be avoided. Generally speaking, once the option is created, it’ll be included within the existing presentational group of options using one of the approaches described. An example of this might be creating a post category for use in tagging entries in a blog.&lt;/p&gt;
&lt;p&gt;While important, this exploration will not be focusing on the curation of the content within an option. Certainly, poor choices in wording or inaccessible options will inhibit the user from making the best choice. The following exploration assumes options are well-crafted.&lt;/p&gt;
&lt;h2 id=&quot;definitions&quot;&gt;Definitions&lt;/h2&gt;
&lt;p&gt;The following patterns will be referenced throughout this exploration:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.microsoft.com/en-us/fluentui#/controls/web/commandbar&quot;&gt;Button groups&lt;/a&gt;: Examples are found in word processing tools for selecting text alignment.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.lightningdesignsystem.com/components/radio-group/&quot;&gt;Radio button groups&lt;/a&gt;: Examples are found in online surveys to rate quality of service.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://react-spectrum.adobe.com/react-spectrum/CheckboxGroup.html&quot;&gt;Checkbox groups&lt;/a&gt;: Examples are found in selecting options to filter products.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://carbondesignsystem.com/components/select/usage&quot;&gt;Native HTML select options&lt;/a&gt;: Examples are found when selecting locations from a list.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://baseweb.design/components/header-navigation/&quot;&gt;Navigational menus&lt;/a&gt;: Examples are found in the header of marketing sites.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://v2.grommet.io/menu&quot;&gt;Context menus&lt;/a&gt;: Examples are found as right-click to copy.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.newskit.co.uk/components/tabs/&quot;&gt;Tab groups&lt;/a&gt;: Examples are found within web pages as secondary navigation.&lt;/li&gt;
&lt;/ul&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;h3 id=&quot;button-group-confusion&quot;&gt;Button group confusion&lt;/h3&gt;&lt;p&gt;What I’ve defined as button group above is not a common button group &lt;a href=&quot;https://component.gallery/components/button-group/&quot;&gt;found amongst most design systems&lt;/a&gt;. The key difference here is the keyboard navigation. A button group is often delivered as just a layout pattern of existing buttons with very little change of visual style and no change in interaction pattern. Each button is accessible via the &lt;code&gt;Tab&lt;/code&gt; key like any other button that isn’t in a group. Because of this, I identify these as groups of individual buttons. There’s nothing stopping most systems to allow any sort of interactive component to exist in these groups; like links for example. For this I recommend providing a layout component instead of something specific for buttons.&lt;/p&gt;&lt;p&gt;However, I am specifically calling out the pattern found in toolbars as it is expected to be a single tab stop, where navigation between buttons is done by arrow keys. Visually these are groups of buttons but with a different and warranted enhancement for accessibility. This pattern can also be found in &lt;a href=&quot;https://www.w3.org/WAI/ARIA/apg/patterns/listbox/&quot;&gt;listboxes&lt;/a&gt;, &lt;a href=&quot;https://www.w3.org/WAI/ARIA/apg/patterns/combobox/&quot;&gt;comboboxes&lt;/a&gt;, and &lt;a href=&quot;https://www.w3.org/WAI/ARIA/apg/patterns/menubutton/&quot;&gt;menus&lt;/a&gt; which also expect arrow key navigation between options within a single tab stop. A &lt;a href=&quot;https://component.gallery/components/segmented-control/&quot;&gt;segmented control&lt;/a&gt; is also of the same family but more related to radio buttons.&lt;/p&gt;&lt;p&gt;To reiterate, this behavior is not meant for usage with most groups of buttons found within an interface, as each is commonly expected to be an individual tab stop.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;It’s also important to define a few terms used for accessibility:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tab stop&lt;/strong&gt;: An area of the interface which is focused by the &lt;code&gt;Tab&lt;/code&gt; key where additional actions can occur. Links and text input fields are clear tab stop examples, but entire lists of options can also be defined as a single tab stop. The area that should be identified as a tab stop is achieved through accessibility best practices for an experience.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Roving tabindex&lt;/strong&gt;: A technique to show focus on an element without the use of the &lt;code&gt;Tab&lt;/code&gt; key. This is done by toggling the &lt;code&gt;tabIndex&lt;/code&gt; of interactive elements. One element in the list will receive a &lt;code&gt;tabIndex=&amp;quot;0&amp;quot;&lt;/code&gt;, while the rest receive &lt;code&gt;tabIndex=&amp;quot;-1&amp;quot;&lt;/code&gt;. This allows the user to re-enter the area using the &lt;code&gt;Tab&lt;/code&gt; key and return focus back to the previously focused element. &lt;a href=&quot;https://www.youtube.com/watch?v=uCIC2LNt0bk&amp;t=6s&quot;&gt;Here’s a video explaining the technique by Rob Dodson&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;h3 id=&quot;accessibility-is-not-easy&quot;&gt;Accessibility is not easy&lt;/h3&gt;&lt;p&gt;There’s a great deal of nuance when attempting to make options accessible. While the w3 attempts to provide &lt;a href=&quot;https://www.w3.org/WAI/ARIA/apg/patterns/&quot;&gt;guidance on best practices&lt;/a&gt;, achieving intended results can be challenging. For example, &lt;a href=&quot;https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/#x6-6-2-managing-focus-in-composites-using-aria-activedescendant&quot;&gt;the guidelines claim&lt;/a&gt; the following:&lt;/p&gt;&lt;blockquote&gt;
&lt;p&gt;If a component container has an ARIA role that supports the &lt;code&gt;aria-activedescendant&lt;/code&gt; property, it is not necessary to manipulate the tabindex attribute and move DOM focus among focusable elements within the container.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;However, &lt;a href=&quot;https://zellwk.com/blog/element-focus-vs-aria-activedescendant/&quot;&gt;testing completed by Zell Liew&lt;/a&gt; concluded that &lt;code&gt;aria-activedescendant&lt;/code&gt; is not well supported for assistive technologies. It’s important to put your best efforts toward marking the options for visibiity to all users and their methods of interaction.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;h2 id=&quot;instant-gratification&quot;&gt;Instant gratification&lt;/h2&gt;
&lt;p&gt;One of the attributes of making a selection is the immediate result of the interaction. Patterns that show new content based on the selection are commonly immediate. For example, navigational menus which redirect to new content should be instant. Buttons that update state like deleting a row of data are also expected to happen quickly.&lt;/p&gt;
&lt;p&gt;This is in contrast to options which expect a user to make selections and then commit those selections in a final action. This is commonly form elements such as radio buttons, checkboxes and HTML selects. The user will choose these options but no updates to the larger system will be made until the user sends a final command. This is often the case for wizard experiences also, where the act of going to the next step submits the options selected before traversing further.&lt;/p&gt;
&lt;p&gt;This means we can divide the patterns into some groups:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Instantaneous&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Button groups&lt;/li&gt;
&lt;li&gt;Navigational menus&lt;/li&gt;
&lt;li&gt;Context menus&lt;/li&gt;
&lt;li&gt;Tab groups&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Confirmational&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Radio button groups&lt;/li&gt;
&lt;li&gt;Checkbox groups&lt;/li&gt;
&lt;li&gt;Native HTML select options&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;links-vs-buttons&quot;&gt;Links vs Buttons&lt;/h2&gt;
&lt;p&gt;Full disclosure, I am a big proponent for clarity of intent. I believe links should have an underline and navigate to new pages, allowing for all the default behaviors an &lt;code&gt;&amp;lt;a/&amp;gt;&lt;/code&gt; tag provides. Buttons should have visible padding and execute actions on the current page, allowing for all the default behaviors a &lt;code&gt;&amp;lt;button/&amp;gt;&lt;/code&gt; tag provides. With that out of the way, there’s additional level of consideration for the difference.&lt;/p&gt;
&lt;p&gt;Links (&lt;code&gt;&amp;lt;a/&amp;gt;&lt;/code&gt; elements) are meant to be individual tab stops &lt;em&gt;always&lt;/em&gt;. This means that if the link is meant to be navigational and sends the user to a new page, the user should be able to go to this element using just the &lt;code&gt;Tab&lt;/code&gt; key.&lt;/p&gt;
&lt;p&gt;For buttons (&lt;code&gt;&amp;lt;button/&amp;gt;&lt;/code&gt; elements), this isn’t the case when prepared as a proper group of related controls. The group is expected to be a single tab stop. Once within the tab stop, a roving tabindex pattern is used to traverse the controls.&lt;/p&gt;
&lt;p&gt;This is a good place to introduce the tab user interface pattern which commonly is treated to look like manilla folder tabs. If the tab interface you prepare expects each tab to be a navigational link that can be revisited using the browser’s URL bar, this means that each tab is an individual tab stop; as link behavior is expected. On the other hand, if each tab is meant to execute a command, thereby keeping the user on the same page, then the entire tab group is one tab stop with roving tabindex navigation. In this way the tab pattern can either act as a navigational menu (using links), or a button group (using buttons). The main decision goes back to the links versus buttons debate to decide which experience to use.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;h3 id=&quot;etymology-of-tab&quot;&gt;Etymology of tab&lt;/h3&gt;&lt;p&gt;Tangentially, the word tab has two definitions for this exploration:&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tab (n.)&lt;/strong&gt;: a second or further document or page that can be opened on a spreadsheet or web browser. Compare also Middle English &lt;em&gt;tab&lt;/em&gt; “strap or string” (mid-15c.), Norwegian dialectal &lt;em&gt;tave&lt;/em&gt; “piece of cloth, rag.”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tab (v.)&lt;/strong&gt;: to press the tab key on a computer or typewriter. As a short form of &lt;em&gt;tabulator key&lt;/em&gt; of a typewriter (later computer) it is recorded from 1916.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Confusingly, you often do not move between tabs using the tab key. Such is the wonderful world of English and computer interfaces.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;Let’s continue to group our patterns:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Instantaneous&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Navigational&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Navigational menus&lt;/li&gt;
&lt;li&gt;Tab groups*&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Functional&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Button groups&lt;/li&gt;
&lt;li&gt;Context menus&lt;/li&gt;
&lt;li&gt;Tab groups*&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Confirmational&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Radio button groups&lt;/li&gt;
&lt;li&gt;Checkbox groups&lt;/li&gt;
&lt;li&gt;Native HTML select options&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;confirmation-follows-form&quot;&gt;Confirmation follows form&lt;/h2&gt;
&lt;p&gt;Returning to the confirmational group, these are patterns most commonly found in forms. This aligns to the way which we would fill out paper forms by entering in all the information first before submitting.&lt;/p&gt;
&lt;p&gt;One of the most clear indications of usage between these patterns of the group is between checkboxes and radio buttons. Checkboxes are meant for selecting more than one option, while radio buttons are used for selecting a single exclusive option.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;h3 id=&quot;keyboard-interactivity-differences&quot;&gt;Keyboard interactivity differences&lt;/h3&gt;&lt;p&gt;Another important difference between checkbox and radio groups is the tab stops. Each checkbox is a single tab stop, while an entire group of radio buttons is a single tab stop with arrow key navigation. This is built into HTML as long as the &lt;code&gt;name&lt;/code&gt; property is correctly applied.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;Interestingly, the native HTML select allows for both configurations (using the &lt;code&gt;multiple&lt;/code&gt; attribute for multiple selections). So the question is, why use the native HTML select when there are other patterns which more clear usage?&lt;/p&gt;
&lt;p&gt;One of the properties of the HTML select is the limited amount of data shown. The element is restrictive to a word or phrase which represents the value for selection. The other patterns allow for much more information. In relation, the select only displays the selected value. This means that it is less likely that the user will review the selection since it requires extra interaction. Laying out all the options as checkboxes or radio buttons help the user consider all the possibilities. Additionally, the HTML select options are not bound to the page layout; its options will exist separately from visual flow. This supports the basis of using checkboxes and radios for options which need more detail from options that are concise.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;h3 id=&quot;multiple-problems&quot;&gt;Multiple problems&lt;/h3&gt;&lt;p&gt;The &lt;code&gt;multiple&lt;/code&gt; attribute which could be added to the HTML select is not a common pattern in user interface design. On desktop devices, additional keys must be introduced in order to choose multiple options and the keys to use vary between desktop operating systems (&lt;code&gt;Ctrl&lt;/code&gt; (windows) or &lt;code&gt;Cmd&lt;/code&gt; (Mac)). Touch devices commonly provide these as checkboxes instead which helps users identify the ability to choose more than one. Due to these properties I would recommend avoiding the HTML select for choosing multiple options and instead present a list of checkboxes or a similar but consistent pattern.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;Let’s break down the options one more time:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Instantaneous&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Navigational&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Navigational menus&lt;/li&gt;
&lt;li&gt;Tab groups*&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Functional&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Button groups&lt;/li&gt;
&lt;li&gt;Context menus&lt;/li&gt;
&lt;li&gt;Tab groups*&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Confirmational&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Verbose&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Exclusive&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Radio button groups&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multiple&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Checkbox groups&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Concise&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Native HTML select options&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;flow&quot;&gt;Flow&lt;/h2&gt;
&lt;p&gt;Here’s a visual representation of our decision tree:&lt;/p&gt;
&lt;pre class=&quot;mermaid&quot; data-astro-cid-qz3dz2lk&gt;  
graph TD
    A[Give user a choice]
    A --&amp;gt; B{Happens immediately?}
    B --&amp;gt;|Yes| C[Instantaneous]
    B --&amp;gt;|No| D[Confirmational]
    C --&amp;gt; E{Directed to new page?}
    E --&amp;gt;|Yes| F[Navigational]
    E --&amp;gt;|No| G[Functional]
    D --&amp;gt; H{Include considerations?}
    H --&amp;gt;|Yes| I[Verbose]
    H --&amp;gt;|No| J[Concise]

&lt;/pre&gt; &lt;script type=&quot;module&quot; defer&gt;
  import mermaid from &apos;https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs&apos;;
  mermaid.initialize({ startOnLoad: true });
&lt;/script&gt;
&lt;p&gt;The flow chart above can help lead a path toward a decision by asking &lt;strong&gt;why&lt;/strong&gt;…&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Why does the user need the action to happen immediately?&lt;/li&gt;
&lt;li&gt;Why does the user need to remain on the page?&lt;/li&gt;
&lt;li&gt;Why does the user need more information about this choice?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Adding purpose to these decisions will ultimately support design decisions with clarity. You can be confident that the pattern chosen is the best one based on the answers to these questions.&lt;/p&gt;
&lt;h2 id=&quot;unavailable-options&quot;&gt;Unavailable options&lt;/h2&gt;
&lt;p&gt;A pattern that may be examined is disabling an option. This could occur because the user hasn’t satisfied criteria or the system is not yet prepared to offer the option. Opinions vary about the decision of showing options that the user is unable to select. I believe the following questions can determine if showing a option as disabled is helpful to the user.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Will the option be available to the user if criteria are met?&lt;/li&gt;
&lt;li&gt;Are the criteria for the option clearly shown in context of the option?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If the answer to the questions are “yes” then it may be appropriate to disable the option. However, note that disabled options aren’t detectable to screen readers and commonly lack sufficient color contrast. Providing the criteria for enabling the option will support these deficits. &lt;a href=&quot;https://www.smashingmagazine.com/2021/08/frustrating-design-patterns-disabled-buttons/&quot;&gt;Vitaly Friedman goes into greater detail at Smashing Magazine&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To put it simply, if it isn’t important why include it in the experience? This segues into the next topic.&lt;/p&gt;
&lt;h2 id=&quot;abundant-options&quot;&gt;Abundant options&lt;/h2&gt;
&lt;p&gt;Presenting the user with too many options introduces a cognitive load and decision paralysis. As described by &lt;a href=&quot;https://lawsofux.com/en/hicks-law/&quot;&gt;Hick’s Law&lt;/a&gt;, the more choices you present, the longer it will take to reach a decision. This might include halting the current flow to return to at a later time. In contrast, limiting the number of options will improve the user experience. While some patterns expect to provide dozens of choices (eg. country of origin), there might be better design choices to capture the same information (eg. text field filtering of the list).&lt;/p&gt;
&lt;p&gt;Use empathy to drive your design choices and your users will be thankful.&lt;/p&gt;</content:encoded></item><item><title>Clarity 2024, Backstage</title><link>https://blog.damato.design/posts/clarity-2024-backstage</link><guid isPermaLink="true">https://blog.damato.design/posts/clarity-2024-backstage</guid><pubDate>Fri, 27 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;&lt;a href=&quot;https://www.clarityconf.com/&quot;&gt;Clarity&lt;/a&gt;, the original design systems conference, just wrapped its 9th iteration this year. I was part of the small group of community volunteers that helps put the event together. I’d like to pull back the curtain behind the technical side of the event; somewhat to play Monday-morning quarterback on things I would have improved in my role on my end.&lt;/p&gt;
&lt;h2 id=&quot;playback&quot;&gt;Playback&lt;/h2&gt;
&lt;p&gt;We planned to have all the talks pre-recorded, so one of the key parts of the setup is to have playback. Having pre-recorded talks helps reduce the need for multiple connections to perform the talk live. It’s hard enough to prepare a presentation, it’ll be even harder to troubleshoot connection problems on top of it.&lt;/p&gt;
&lt;p&gt;To do this, I was looking for a dedicated device that would handle playback. In my mind, I was expecting to find a modern device that could provide clean HDMI out, display local time remaining for the media, and physical buttons to navigate files and playback. In all my searching, I couldn’t find the perfect device with those requirements. It’s wild to me that this doesn’t readily exist.&lt;/p&gt;
&lt;p&gt;The fact is, much of this is done with software now. Usually you’ll have folks who stream handling everything with a single computer with &lt;a href=&quot;https://obsproject.com/&quot;&gt;OBS&lt;/a&gt; and a &lt;a href=&quot;https://www.elgato.com/us/en/p/stream-deck-mk2-black&quot;&gt;StreamDeck&lt;/a&gt;. This is certainly a viable solution but I’m old school. I’ve been streaming for a long time; before Twitch, before even YouTube. I’d take a RCA encoder and hook that up to stream super low-quailty camcorder video using RealPlayer back in the day. So it is important to me that there are separation of concerns. If you have everything being handled in a single spot, if that spot goes down, everything goes down.&lt;/p&gt;
&lt;p&gt;The video switcher I use could load the videos inside of it, but I believe a switcher shouldn’t be used to navigate and play the videos. It’s main role is to cue and stream a media source from the outside. So for playback, I ended up using my wife’s spare laptop. This is a subpar solution for a few reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You can’t navigate the files while media is playing.&lt;/li&gt;
&lt;li&gt;You’ll have the system UI show during some setup.&lt;/li&gt;
&lt;li&gt;You can’t see time remaining on the video to cue talent.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Thank goodness the spacebar was the physical button to start/stop the media. Though I wish the screen wouldn’t have flashed the icons in the corner when doing so. A quality media player wouldn’t need to show that in the feed but in some exterior menu instead. I do wish this is something that can come to the prosumer market or perhaps something that could be more seriously considered in current hardware switchers. My hardware switcher has 8 slots for media but preparing the media is a hassle through the menus.&lt;/p&gt;
&lt;p&gt;This laptop was also the “Character Generator”, which is a fancy term for a source that can show text and graphics. This means that I can’t prep any text or graphics for the next segment until I’m clear from the playback. I’d have to cue up the next items during the live Q&amp;amp;A.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;Quick note about the interstitial screens. They were all originally designed by &lt;a href=&quot;https://www.laurenloprete.com/&quot;&gt;Lauren LoPrete&lt;/a&gt;. I took the general layout as reference and made a website from them (using &lt;a href=&quot;https://astro.build&quot;&gt;Astro&lt;/a&gt; because of course I did). That made it easy to navigate to the next speaker or even change the text with a &lt;code&gt;contenteditable&lt;/code&gt; attribute to make custom announcements.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;h2 id=&quot;live-qa&quot;&gt;Live Q&amp;amp;A&lt;/h2&gt;
&lt;p&gt;It was important to have some live element to this event so it wouldn’t just be a playlist. When we were in the early stages of coordinating, &lt;a href=&quot;https://johnfallsopp.com/&quot;&gt;John Allsopp&lt;/a&gt; warned that broadcasting live, especially a conversation, is very tricky and prone to many problems. He’s absolutely right, I definitely wouldn’t recommend trying to do this if you haven’t before. There’s a lot that can go wrong or be otherwise frustrating. I say that from experience because my master’s degree is in live event production and this is the sort of thing that I focused a lot of attention on. Back then, we even had some prototype devices for broadcasting Skype calls and successfully did live chats on a weekly basis. The technology is certainly better now, but still not perfect, especially for a scrappy show like this.&lt;/p&gt;
&lt;p&gt;To do the live Q&amp;amp;A, I wanted to leverage a reliable call technology where I could pull the source media out to the feed for later compositing. Zoom is what I chose, along with the help of a program called &lt;a href=&quot;https://www.videocom.at/zoom-bridge&quot;&gt;Zoom Bridge&lt;/a&gt; which creates &lt;a href=&quot;https://ndi.video/&quot;&gt;NDI&lt;/a&gt; sources from the call. I was unfamiliar with the NDI protocol, but it’s a new way of sending media over the network. This means you can have media playing over a network switch and devices can find that media to be played.&lt;/p&gt;
&lt;p&gt;The thing about this technique is that it is bandwidth intensive so I was very worried about attempting to create NDI media streams on top of the bandwidth used for the live stream itself. I took some time to try and make a local network specifically for the NDI sources but I couldn’t figure it out. I’m not an network engineer. The best I can normally do is release/renew an IP config. Ultimately, the tech checks seemed to show this shouldn’t be a problem and after completing the event, it’s clear it wasn’t an issue. I wonder how many NDI sources it would take for it to be noticeable.&lt;/p&gt;
&lt;p&gt;Now, that I had NDI sources from Zoom, I had to get them out of the computer and into the switcher. I purchased a NDI to HDMI decoder to get the streams to convert to HDMI for the switcher, however it seems that each decoder could only handle one source. That would mean I’d need two devices, one for each call participant. Instead, I decided to use OBS. OBS has NDI input source options and can also export the program as an NDI source. So, I made a few simple scenes for the live Q&amp;amp;A in OBS, prepared some hotkeys for the number pad on the keyboard, and sent the whole thing out as a single NDI source to the switcher.&lt;/p&gt;
&lt;p&gt;The flow during the Q&amp;amp;A portions worked fairly well. Our speaker would join the private Zoom call where Jina and I were waiting. I’d set the participant as the new source in the Zoom Bridge, which gets the media into the premade OBS scenes. After the presentation video finishes, I’d switch to OBS and cue Jina. Then all of the live Q&amp;amp;A switching would happening with OBS and the 3 scenes: Jina, the speaker, and the split screen (also designed by Lauren). This ended up working better than I was expecting. In my experience, I’d used to having all switching happen from one station because it is easy to confuse otherwise. Separating the live Q&amp;amp;A switching from the main program switching helped focus attention to the flow of the conversation. Also helped since my switcher doesn’t have many source inputs and OBS could take many more through software.&lt;/p&gt;
&lt;p&gt;Like I said, I’d still rather not use a computer as a source because there’s too many things that can go wrong. This was the case for the first day. During the first day, the Zoom connection was awful. It was hard to tell with just Jina starting since it could have only been her connection, but when Dan signed on it was very clear that my connection was the problem. It was then I noticed the Zoom computer was connected to the house WiFi instead of the main fiber. After I switched to the main fiber, everyone had a much better connection with one flaw.&lt;/p&gt;
&lt;p&gt;I could see in my studio that there was an audio delay, and I also received a few reports on it. I had no good way of adjusting this during the live stream because of another topic I’ll bring up soon. At the end of the first day, Jina and I did a quick tech check where I’d focus on synchronizing the audio with the video. Apparently we were an entire second (1000ms) off. I was able to enter a delay in OBS to prepare for the next day.&lt;/p&gt;
&lt;p&gt;During the next day, we did another test on the delay. In doing this I found there was no delay! My assumption is that when I switched the Zoom WiFi during the stream, the sources became slightly out of sync. Now that it was a new Zoom call, it must have re-synchronized. So all of the live Q&amp;amp;A portions on the second day were executed very well, and I’m kicking myself for not doing more testing to identify the problems that happened on the first day. A learning experience for sure.&lt;/p&gt;
&lt;p&gt;I do wish that there was prosumer device that could handle this stuff more gracefully. Maybe with all the great tech &lt;a href=&quot;https://rode.com/en-us&quot;&gt;RØDE&lt;/a&gt; has been making they could consider it in their next device.&lt;/p&gt;
&lt;h2 id=&quot;audio&quot;&gt;Audio&lt;/h2&gt;
&lt;p&gt;In just about any event, audio is the most important facet. It’s one thing to be showing images but the content that comes from the audio is most noticeable. This is where I really would have loved to have that dedicated Zoom device instead of a computer. The way my computer settled audio was to simply output the desktop audio to the stream. This would be the same audio that you might hear in the Zoom call you’d have in a meeting. It will include all of the audio for the computer in a single channel out to your speakers or headset, except your microphone audio. I don’t know if the NDI sources would have accepted individual channels of audio as sources in OBS. I think I tried it a few times and never got more than the desktop audio working.&lt;/p&gt;
&lt;p&gt;However, because OBS decided that it wanted to use desktop audio as the output, that apparently meant that if I changed my desktop audio output to be my headset, that the audio would &lt;em&gt;not&lt;/em&gt; go out to the switcher. That meant I needed to keep the desktop audio as the source, and that the Zoom call would fill my room with sound. This was a problem since I was trying to monitor the live stream which was on a slight delay from the computer. This was incredibly distracting. To provide some relief, I’d keep myself on mute for the Zoom call to spare others from hearing the stream through my microphone. I did try to use headphones on the switcher toward the end of the first day, but that was also awkward when coordinating over the Zoom call.&lt;/p&gt;
&lt;p&gt;If I had a better understanding of how the computer and OBS handle routing audio, I would have rathered having separate audio channels for each person, and to have the Zoom call in the headset and the program playing in the room. This was probably most apparent when I went live on camera in the middle of the second day. This was unplanned so I wasn’t sure what sort of audio setup I’d need to adjust. I suspect the echo that was occuring was either the program playback (that I thought I muted) or the Zoom audio coming from the computer. Either way, I did my best to ride the OBS mute button to limit the amount of noise. Hopefully it wasn’t too distracting.&lt;/p&gt;
&lt;p&gt;That’s another big reason why I like hardware solutions over software. It’s very clear how the sources are traveling into the equipment as physical cables. I’m sure plenty of folks can relate to struggling with Bluetooth devices connecting and disconnecting, OS switching audio settings as a result. This is actually what happens at the very beginning of Dan’s presentation. I disconnected a source I wasn’t using on the playback laptop and the OS switched to the internal speakers instead of over HDMI where it was originally connected. Luckily I noticed this quickly seeing empty audio levels and did a quick restart. This doesn’t happen when working with hardware, the audio is always connected.&lt;/p&gt;
&lt;h2 id=&quot;dont-try-this-at-home&quot;&gt;Don’t try this at home&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/images/ds-house-basement.jpg&quot; alt=&quot;The basement with all the tech equipment&quot;/&gt;&lt;/p&gt;
&lt;p&gt;In reality for a production like this, there should be at the very least 4 people handling the parts. One for the video playback, one for handling live Q&amp;amp;A, one for character generation and one for the stream itself. That’s not counting the stage management job that my wife &lt;a href=&quot;https://www.linkedin.com/in/jipdamato/&quot;&gt;Jennifer&lt;/a&gt; graciously volunteered to handle. We were able to get nearly every speaker cued up and live for the 2 day event, with only one person that had a schedule conflict.&lt;/p&gt;
&lt;p&gt;After moving to tech I never thought I’d be running live coordinated events again but I’m glad Jina and the team gave us a chance to do it. Many thanks to the speakers, the volunteers, and the community for all its support.&lt;/p&gt;
&lt;p&gt;Will the &lt;a href=&quot;https://ds.house&quot;&gt;Design Systems House&lt;/a&gt; promote itself with a live event production side business? It depends™ 😊&lt;/p&gt;</content:encoded></item><item><title>Classname soup</title><link>https://blog.damato.design/posts/classname-soup</link><guid isPermaLink="true">https://blog.damato.design/posts/classname-soup</guid><pubDate>Tue, 17 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;The internet blew up again regarding CSS frameworks and there have been no shortage of responses. While this could just be more fuel to the fire, I hope this will be evergreen and reflect on any similar approaches that are developed over time. This also has the benefit of avoiding the name of any single framework in particular and instead comment on the direction as a whole.&lt;/p&gt;
&lt;h2 id=&quot;lightbulb-moment&quot;&gt;Lightbulb moment&lt;/h2&gt;
&lt;p&gt;Recently, I realized exactly why I was aversed to utility class resources after watching &lt;a href=&quot;https://www.youtube.com/watch?v=lHZwlzOUOZ4&quot;&gt;Fireship.io’s video&lt;/a&gt; responding to the recent debates. The lightbulb lit for me specifically at this quote.&lt;/p&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://www.youtube.com/watch?v=lHZwlzOUOZ4&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;The benefit is that you don’t have all these arbitrary classnames anymore and know exactly which styles apply to it.&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://www.youtube.com/watch?v=lHZwlzOUOZ4&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;Fireship.io&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;#naming-is-hard&lt;/strong&gt; strikes again. There’s two parts in the quote that I’ll touch upon.&lt;/p&gt;
&lt;h3 id=&quot;knowing-styles-exactly&quot;&gt;Knowing styles exactly&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Declarative classnames are not scalable.&lt;/strong&gt; In a world where we lean hard into semantic tokens to help describe the experience in terms of purpose over value, we release control of the final presentation of the design to be informed by tokens way up the stack. We no longer prescribe that this card border thickness in this very specific spot must be &lt;code&gt;3px&lt;/code&gt;. It should instead be applied by way of a mapping of a semantic token to a value in a theme curation exercise.&lt;/p&gt;
&lt;p&gt;Therefore, it is not flexible to prescribe themable style via a classname. Using &lt;code&gt;.border-teal-darkest&lt;/code&gt; has the same problem as having a token which is &lt;code&gt;--border-teal-darkest&lt;/code&gt; applied directly to a component. &lt;a href=&quot;/posts/tokens-as-intents&quot;&gt;It’s not semantic&lt;/a&gt;. While you could dive deep into this by adding &lt;em&gt;more&lt;/em&gt; classnames to address themes, it will become unwieldly. Additionally, I’ve also thoroughly described &lt;a href=&quot;/posts/ondark-virus&quot;&gt;the perils of calling something “dark”&lt;/a&gt; which also has this vulnerability.&lt;/p&gt;
&lt;p&gt;It’s hard to think in this abstract way, as folks who have been building UIs to specification have been forced into “pixel-perfection” for years. While we don’t use the term much anymore, the effects remain. Designers will be disappointed if they expect to have exactly this color or precisely this thickness when working within their one context when multiple exist.&lt;/p&gt;
&lt;h3 id=&quot;reasoned-classnames&quot;&gt;Reasoned classnames&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;If it has a purpose, it should have a name.&lt;/strong&gt; The screenshot example in the video during the quote shows a large red ‘x’ over some CSS with the following classnames: &lt;code&gt;.main-navbar&lt;/code&gt;, &lt;code&gt;.main-navbar-list&lt;/code&gt;, &lt;code&gt;.main-navbar-list-item&lt;/code&gt;. From this list I can tell exactly what component will be affected by these styles. It should only exist in one part of the project.&lt;/p&gt;
&lt;p&gt;But what if it doesn’t? That’s the whole problem with naming. I could have another &lt;code&gt;.main-navbar&lt;/code&gt; or worse &lt;code&gt;.btn&lt;/code&gt; provided some some third-party library which then starts a style battle. I’m a lover, not a fighter!&lt;/p&gt;
&lt;p&gt;One answer is to have a standardized method of coming up with names; similar to the semantic token scheme perhaps including a namespace to distinguish between ownership. I believe a first approach could be to have the semantic token name and the classname to be near identical, differing only in the property that the token should be assigned being encoded into the token.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.ds-main-navbar&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  background-color&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--ds-main-navbar-background)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In practice, I don’t recommend being this specific but the concept is important. If you are too specific in token names, you’ll wind up with thousands of tokens to describe every property of themable appearance. A better approach is to be slightly generic in the semantic token to cover several possible uses, but remain specific in the classname.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-comment)&quot;&gt;/* These are specific styles for the main navigational bar component */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.ds-main-navbar&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;  /* token covers the background for all navigational surfaces */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  background-color&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--ds-surface-navigation-background)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The token can be applied to other similar surfaces but the classname identifies this specific component and the styles it needs. This can be similar to the &lt;a href=&quot;https://en.bem.info/&quot;&gt;BEM (Block Element Modifier) structure&lt;/a&gt; for classnames which identifies the parts of a component.&lt;/p&gt;
&lt;p&gt;This functions well for themable properties, but what about layout? Perhaps you don’t want to continue to type out all 59 characters of &lt;code&gt;grid-template-colums: repeat(auto-fit, minmax(240px, 1fr));&lt;/code&gt; over and over again. I think that’s a reasonable critism to have. In that case, it sound like you might have a new component on your hands.&lt;/p&gt;
&lt;h2 id=&quot;component-driven-development&quot;&gt;Component driven development&lt;/h2&gt;
&lt;p&gt;In my opinion, the best approach is &lt;em&gt;to not have classes at all&lt;/em&gt;. Instead I believe we should scope the styles to uniquely to the component. This can be accomplished in some CSS frameworks or using &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM&quot;&gt;Shadow DOM&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Using the Shadow DOM technique, you can leverage &lt;code&gt;id&lt;/code&gt; instead of &lt;code&gt;class&lt;/code&gt; which further demonstrates that there should only be one of these elements within the component’s scope. In the Shadow DOM, the elements and styles aren’t exposed to the outside DOM so duplication across different components is valid.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;  #main-nav&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    background-color&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--ds-surface-navigation-background)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;nav&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;main-nav&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;    &amp;lt;!-- Generated on mount of the Custom Element --&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;nav&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You could also avoid these attributes altogether in the Shadow DOM if the component is simple and semantic.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  nav&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    background-color&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--ds-surface-navigation-background)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;nav&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;    &amp;lt;!-- Generated on mount of the Custom Element --&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;nav&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In CSS-in-JS libraries, this implementation might be more concise.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; MainNav&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; styled&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;nav&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  background-color: var(--ds-surface-navigation-background);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Not all of these components need to be exposed to users. Some of them are internal where the names won’t be so critical. For example, the &lt;code&gt;.main-navbar-list&lt;/code&gt; which is internal to the &lt;code&gt;.main-navbar&lt;/code&gt; is not important to external users. In both of the directions shown above, you can target elements even more generically if you possess anxiety over naming.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-string-expression)&quot;&gt;nav&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;  /* this is the list but I don&amp;#39;t want to name it */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, I wouldn’t recommend this since it goes against the first point that if it exists, it should have a name. Just be comforted that internal naming is much easier to iterate on.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;Some things might not make sense as a component and exist better as a utility. The historic &lt;a href=&quot;https://css-tricks.com/inclusively-hidden/&quot;&gt;&lt;code&gt;.sr-only&lt;/code&gt;&lt;/a&gt; meant for hiding content visually while remaining accessible to assistive technology might be better suited using an attribute because it is not dependent on other factors for a consistent outcome and is presented imperatively. Not to mention, there’s really nothing visual about it.&lt;/p&gt;&lt;p&gt;Though there’s also nothing stopping you from creating a &lt;code&gt;&amp;lt;sr-only/&amp;gt;&lt;/code&gt; web component which achieves the same result with more code.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;In lieu of scoping styles, create a standardized naming strategy that keeps classnames semantic and you’ll be better prepared to support a scalable experience.&lt;/p&gt;</content:encoded></item><item><title>Clickable cards</title><link>https://blog.damato.design/posts/clickable-cards</link><guid isPermaLink="true">https://blog.damato.design/posts/clickable-cards</guid><pubDate>Fri, 08 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;While having a good time with internet friends on Bluesky, I saw &lt;a href=&quot;https://bsky.app/profile/philanelson.bsky.social/post/3lafk37shyc2l&quot;&gt;a thread asking about Josh Comeau’s website&lt;/a&gt;, specifically asking about why the entire card isn’t clickable. Josh’s replies concerning usability is spot on, and I’ve definitely been naughty doing the typical &lt;code&gt;display: block&lt;/code&gt; on a &lt;code&gt;&amp;lt;a/&amp;gt;&lt;/code&gt; element right here on the blog homepage. The replies in the thread also have some good suggestions but I was wondering if there was alternative. I have two main criteria:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use HTML &amp;amp; CSS only, so there’s no need to listen for additional behavior.&lt;/li&gt;
&lt;li&gt;Ensure that it meets user expectations both in terms of accessibility and also visually.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I think I have something…&lt;/p&gt;
&lt;h2 id=&quot;forgotten-memories&quot;&gt;Forgotten memories&lt;/h2&gt;
&lt;p&gt;In the list of HTML tags that people forget about, there’s two that are very often unused: &lt;code&gt;&amp;lt;map/&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;area/&amp;gt;&lt;/code&gt;. These are meant to be used with an associated &lt;code&gt;&amp;lt;img/&amp;gt;&lt;/code&gt; so a user can click defined regions of an image. &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/area&quot;&gt;The example for &lt;code&gt;&amp;lt;area/&amp;gt;&lt;/code&gt; on MDN&lt;/a&gt; has a good sample of this.&lt;/p&gt;
&lt;p&gt;The idea is that you define the areas’ shapes using some attributes and then group them into the &lt;code&gt;&amp;lt;map/&amp;gt;&lt;/code&gt;. Then you assign that to the &lt;code&gt;&amp;lt;img/&amp;gt;&lt;/code&gt; using &lt;code&gt;usemap&lt;/code&gt;, which is a reference to the &lt;code&gt;&amp;lt;map/&amp;gt;&lt;/code&gt;. Each &lt;code&gt;&amp;lt;area/&amp;gt;&lt;/code&gt; can accept many of the same attributes of an &lt;code&gt;&amp;lt;a/&amp;gt;&lt;/code&gt;, most importantly including &lt;code&gt;href&lt;/code&gt; and &lt;code&gt;target&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So what if we could include a visually hidden image the size of the card and then add an &lt;code&gt;href&lt;/code&gt; to the entire area of the image? Let’s take a look:&lt;/p&gt;
&lt;h2 id=&quot;sourcery&quot;&gt;Sourcery&lt;/h2&gt;
&lt;p&gt;We certainly don’t want to make a request for an image that is only being used to support this behavior. We’d want some resource that was quick and hard-coded. Stack Overflow has a topic on “&lt;a href=&quot;https://stackoverflow.com/questions/2570633/smallest-filesize-for-transparent-single-pixel-image&quot;&gt;smallest filesize for transparent single pixel image&lt;/a&gt;” which is exactly what we need. I’ll add a few additional attributes as well.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;img&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; src&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEAAAAALAAAAAABAAEAAAIBAAA=&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;    aria-hidden&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;    height&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;100%&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;    width&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;100%&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;    usemap&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;#name&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;aria-hidden=&amp;quot;true&amp;quot;&lt;/code&gt; is added because this image is strictly to support the area that we want to click, we don’t want to expose it in the accessibility tree. The &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes are ensuring that the image is the full size of the container it is placed within. And the &lt;code&gt;usemap=&amp;quot;#name&amp;quot;&lt;/code&gt; is meant to reference a &lt;code&gt;&amp;lt;map name=&amp;quot;name&amp;quot;/&amp;gt;&lt;/code&gt; somewhere in the page.&lt;/p&gt;
&lt;p&gt;Next we’ll make the &lt;code&gt;&amp;lt;map/&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;area/&amp;gt;&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;card&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;area&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        alt&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;Design Systems Hot Takes&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        href&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;https://blog.damato.design&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        shape&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;default&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        target&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;_blank&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;href&lt;/code&gt; and &lt;code&gt;target&lt;/code&gt; should be clear. The &lt;code&gt;shape=&amp;quot;default&amp;quot;&lt;/code&gt; tells the &lt;code&gt;&amp;lt;area/&amp;gt;&lt;/code&gt; to be the same size as the &lt;code&gt;&amp;lt;img/&amp;gt;&lt;/code&gt;. The &lt;code&gt;alt&lt;/code&gt; is the same text you’d expect for images, except here we’re using it as the label for the link. On MDN, it mentions that this is used for browsers that don’t show images.&lt;/p&gt;
&lt;p&gt;Finally, let’s put all of this in a card:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;card&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt;card-contents&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;quot;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        Card contents&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;card&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;area&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;            alt&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;Design Systems Hot Takes&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;            href&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;https://blog.damato.design&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;            shape&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;default&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;            target&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;_blank&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;img&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; src&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEAAAAALAAAAAABAAEAAAIBAAA=&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        aria-hidden&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        height&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;100%&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        width&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;100%&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        usemap&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;#name&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;Note that this could be optimized such that the &lt;code&gt;&amp;lt;img/&amp;gt;&lt;/code&gt; is added &lt;em&gt;once&lt;/em&gt; and all &lt;code&gt;&amp;lt;map/&amp;gt;&lt;/code&gt; elements in every card can use the same &lt;code&gt;name&lt;/code&gt; reference. Then the only unique element to each card would be the attributes in the &lt;code&gt;&amp;lt;area/&amp;gt;&lt;/code&gt;. This means you’re only “rendering” a single image.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;h2 id=&quot;styles&quot;&gt;Styles&lt;/h2&gt;
&lt;p&gt;Now for some styles, and there isn’t a lot so I’m going to write everything below and explain:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.card&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    display&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; grid&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-function)&quot;&gt;.card:focus-within&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    outline&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; auto Highlight&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    outline&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; auto -webkit-focus-ring-color&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-function)&quot;&gt;.card&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; :not&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    grid-area&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1 / 1 / -1 / -1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-function)&quot;&gt;.card&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; map&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    position&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; absolute&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    transform&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; scale&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(0)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First, the grid styles are a different way of getting the direct children to fill the container. Traditionally we’d place &lt;code&gt;position: relative;&lt;/code&gt; on the &lt;code&gt;.card&lt;/code&gt; and then &lt;code&gt;position: absolute;&lt;/code&gt; on the &lt;code&gt;img&lt;/code&gt;. However, that could cause layering problems since &lt;code&gt;position&lt;/code&gt; creates a new &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_positioned_layout/Understanding_z-index/Stacking_context&quot;&gt;stacking context&lt;/a&gt;. The grid properties here will make the children fill the container.&lt;/p&gt;
&lt;p&gt;Next, the &lt;code&gt;.card:focus-within&lt;/code&gt; listens for when the &lt;code&gt;area&lt;/code&gt; element is focused and applies a ring to identify this card is ready to be interacted with. You can add your own indication, I’m using the &lt;a href=&quot;https://css-tricks.com/copy-the-browsers-native-focus-styles/&quot;&gt;default browser styles&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Finally, the styles for &lt;code&gt;map&lt;/code&gt; ensure that it doesn’t take up any space in the composition but is still reachable with assistive technologies. The styles within here are a new way of supporting &lt;a href=&quot;https://www.scottohara.me/blog/2017/04/14/inclusively-hidden.html&quot;&gt;visually hidden&lt;/a&gt; so the &lt;code&gt;alt&lt;/code&gt; text is reachable.&lt;/p&gt;
&lt;p&gt;I have &lt;a href=&quot;https://codepen.io/fauxserious/pen/OJKaOZj&quot;&gt;a CodePen of the implementation&lt;/a&gt; below, including the traditional block anchor:&lt;/p&gt;
&lt;iframe height=&quot;500&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;Clickable card!&quot; src=&quot;https://codepen.io/fauxserious/embed/OJKaOZj?default-tab=html%2Cresult&quot; frameborder=&quot;no&quot; loading=&quot;lazy&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/fauxserious/pen/OJKaOZj&quot;&gt;
Clickable card!&lt;/a&gt; by Donnie D’Amato (&lt;a href=&quot;https://codepen.io/fauxserious&quot;&gt;@fauxserious&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;results&quot;&gt;Results&lt;/h2&gt;
&lt;p&gt;So now this should allow for all the normal link behavior; hovering to see the link destination, right-click to open in new window, etc.. This also allows for some more interesting options. Perhaps you’d want to allow for &lt;em&gt;parts&lt;/em&gt; of the card to be clickable so that other text can be selectable, you could adjust the position of the &lt;code&gt;&amp;lt;img/&amp;gt;&lt;/code&gt; to cover the area. Maybe you’d want to conditionally allow text in the card to be selectable. Use CSS to hide the &lt;code&gt;&amp;lt;img/&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Have I tested anything else past what I’ve said here? Nope. But, maybe someone can be further inspired and continue down this path.&lt;/p&gt;
&lt;p&gt;Is this really any different from adding a display block &lt;code&gt;&amp;lt;a/&amp;gt;&lt;/code&gt; and filling it inside the card like it is done with the &lt;code&gt;&amp;lt;img/&amp;gt;&lt;/code&gt;? &lt;em&gt;Sort of&lt;/em&gt;, since it would still need content for assistive technologies to read, and you’d need to wrap the content in a &lt;code&gt;&amp;lt;span/&amp;gt;&lt;/code&gt; and visually hide it specifically for ATs, or maybe use an &lt;code&gt;aria-label&lt;/code&gt;. Maybe it’s easier, but maybe there’s something to the approach above that makes it better in some way?&lt;/p&gt;
&lt;p&gt;At the very least, I bet you probably learned about some HTML elements you haven’t heard of. 😉&lt;/p&gt;</content:encoded></item><item><title>Close thy enemy</title><link>https://blog.damato.design/posts/close-thy-enemy</link><guid isPermaLink="true">https://blog.damato.design/posts/close-thy-enemy</guid><pubDate>Mon, 09 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;You’ve seen it before, an ‘x’ at the corner of a surface which will allow the user to exit that surface. In design, it seems simple to just place the button at the top corner. To engineer this, we have a few options:&lt;/p&gt;
&lt;h2 id=&quot;absolute-position&quot;&gt;Absolute Position&lt;/h2&gt;
&lt;p&gt;The first option most folks might consider is something like the following:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.surface&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  position&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; relative&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-function)&quot;&gt;.surface&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.close&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  position&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; absolute&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;  /* https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Logical_Properties */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  inset-block-start&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;/* logical property for &amp;quot;top&amp;quot; */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  inset-inline-end&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;/* logical property for &amp;quot;right&amp;quot; */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Many design system component libraries use this approach:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ant.design/components/modal&quot;&gt;Ant Design System&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://baseweb.design/components/modal/&quot;&gt;Base Web (Uber)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://carbondesignsystem.com/components/modal/code/&quot;&gt;Carbon Design System (IBM)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://chakra-ui.com/docs/components/modal/usage&quot;&gt;Chakra UI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://primer.style/react/Dialog&quot;&gt;Github Primer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://reach.tech/dialog/&quot;&gt;Reach UI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.design/product/components/modals/&quot;&gt;Stacks (StackOverflow)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The problem with this approach is the way that &lt;code&gt;position: absolute&lt;/code&gt; works. When applying &lt;code&gt;position: absolute;&lt;/code&gt; to an element, it takes that element out of the normal flow of the document. This means that other elements cannot interact with this element.&lt;/p&gt;
&lt;p&gt;In some configurations for the above components, the content (usually the title) &lt;em&gt;could&lt;/em&gt; appear visually layered below the close button.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/modal-button-collide.png&quot; alt=&quot;Curated text that visually collides with the close button in Github Primer&quot;/&gt;&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;Even if you think you control the content, assume that you don’t. User preferences can influence the content display, either by size, translation, or otherwise. Be prepared for the content to vary.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;Some implementations solve this for by providing enough padding to the content area so the button never collides. However, this often results in an imbalance of padding and may not be desirable from design.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/modal-padding-imbalance.png&quot; alt=&quot;Text never touches the far edge because there&apos;s more padding for the close button in IBM Carbon&quot;/&gt;&lt;/p&gt;
&lt;h2 id=&quot;flex-header&quot;&gt;Flex header&lt;/h2&gt;
&lt;p&gt;Another method is to add the button as a flex child to a header of the surface.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.surface&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; .header&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  display&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; flex&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-function)&quot;&gt;.surface&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; .header&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.close&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  margin-inline-start&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; auto&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here’s a list of components across design systems using this approach:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://atlassian.design/components/modal-dialog/examples&quot;&gt;Atlassian Design&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.microsoft.com/en-us/fluentui#/controls/web/modal&quot;&gt;Microsoft Fluent&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://paste.twilio.design/components/modal/&quot;&gt;Twilio Paste&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://polaris.shopify.com/components/modal#navigation&quot;&gt;Shopify Polaris&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://shoelace.style/components/dialog&quot;&gt;Shoelace UI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While this avoids a collision between the button and content, it also requires that the header exist which will be at least the height of the close button. In cases where additional header content doesn’t exist this displays a large forehead before the content.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/modal-large-forehead.png&quot; alt=&quot;Removing title results in large space above the content in Twilio Paste&quot;/&gt;&lt;/p&gt;
&lt;p&gt;So if the surface doesn’t have a title, the amount of space might not be desirable by design. Certainly, if design is attempting to curate the title, this might have some control. However, incorrect alignment could also result in the close button centering within the header instead of pinning to the corner.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/modal-centered-header.png&quot; alt=&quot;A large amount of header content can visually center button in Shoelace UI&quot;/&gt;&lt;/p&gt;
&lt;h2 id=&quot;unique-alternatives&quot;&gt;Unique alternatives&lt;/h2&gt;
&lt;p&gt;There are some other approaches. &lt;a href=&quot;https://www.lightningdesignsystem.com/components/modals/&quot;&gt;Salesforce Lightning includes the button outside the modal&lt;/a&gt; which might not work for other surfaces. &lt;a href=&quot;https://www.lightningdesignsystem.com/components/alert/&quot;&gt;Their alert component&lt;/a&gt; uses the &lt;code&gt;position: absolute;&lt;/code&gt; technique as an example which will have similar problems as described above. &lt;a href=&quot;https://spectrum.adobe.com/page/alert-dialog/&quot;&gt;Adobe Spectrum avoids the ‘x’ button entirely&lt;/a&gt; and provides an explicit action to close the surface. However, &lt;a href=&quot;https://spectrum.adobe.com/page/in-line-alert/&quot;&gt;their alert component&lt;/a&gt; suffers from problems using the icon accessory in relation to the title in this similar layout.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/modal-alert-icon.png&quot; alt=&quot;A large amount of header content can shrink the icon in Adobe Spectrum&quot;/&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-buoyant-approach&quot;&gt;The “buoyant” approach&lt;/h2&gt;
&lt;p&gt;Let’s be clear about some requirements. If design is expecting a close button to appear at the top corner:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Padding around the surface should be visually consistent.&lt;/li&gt;
&lt;li&gt;The close button should never move from the corner.&lt;/li&gt;
&lt;li&gt;The content in the surface should not collide with the close button.&lt;/li&gt;
&lt;/ul&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;These requirements are meant for surfaces that are text heavy. A surface which has a full-bleed media (eg., image or video) which spans the width of the surface will have other problems. The normal &lt;code&gt;position: absolute;&lt;/code&gt; treatment would probably work well in this case and then ensuring that the button has sufficient contrast against the media it appears above.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;We can leverage two features of CSS to get an intended result.&lt;/p&gt;
&lt;h3 id=&quot;recent-relative-ancestor&quot;&gt;Recent relative ancestor&lt;/h3&gt;
&lt;p&gt;In order to get an element to be positioned relative to another, we need to create a relationship. In the case of &lt;code&gt;position: absolute;&lt;/code&gt; this relation doesn’t need to be between a direct parent and child. It can be &lt;strong&gt;any ancestor&lt;/strong&gt;. This means we can have a distant child be positioned to ancestor located up the tree.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.surface&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  position&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; relative&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-function)&quot;&gt;.surface&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.close&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  position&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; absolute&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is no different from the methods we’ve critized above &lt;em&gt;except&lt;/em&gt; that the &lt;code&gt;button.close&lt;/code&gt; element is a child of another element; our secret sauce…&lt;/p&gt;
&lt;h3 id=&quot;floats&quot;&gt;Floats!&lt;/h3&gt;
&lt;p&gt;The way we get text to wrap around elements is by using  the &lt;code&gt;float&lt;/code&gt; property. We’ll float the button toward the right, so that content moves around it.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-string-expression)&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.floater&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  float&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; right&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;/* inline-end */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;While we’d like to use CSS Logical Properties for the float, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/float#browser_compatibility&quot;&gt;they aren’t well supported&lt;/a&gt;. You’ll probably need to adjust the type of float based on the &lt;code&gt;dir&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;dir&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;rtl&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.floater&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  float&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; left&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;Then our HTML should be setup in the following manner:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;surface&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;floater&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;close&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;×&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;  &amp;lt;!-- Surface content goes here --&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You’ll need a bunch of other styles to finesse the size of the floating element and button in relation to the content. The final result should look something like this:&lt;/p&gt;
&lt;iframe height=&quot;500&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;buoyant button&quot; src=&quot;https://codepen.io/fauxserious/embed/ExpWjzL?default-tab=html%2Cresult&amp;editable=true&quot; frameborder=&quot;no&quot; loading=&quot;lazy&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/fauxserious/pen/ExpWjzL&quot;&gt;
buoyant button&lt;/a&gt; by Donnie D’Amato (&lt;a href=&quot;https://codepen.io/fauxserious&quot;&gt;@fauxserious&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 here. In the demo above, the blue box represents the &lt;code&gt;span.floater&lt;/code&gt; element dimensions. Note that because we’re using &lt;code&gt;position: absolute;&lt;/code&gt; for the &lt;code&gt;button&lt;/code&gt; element child, it’s not visually inside the &lt;code&gt;span.floater&lt;/code&gt; but instead positioned relative to the surface. We set the dimensions of the &lt;code&gt;span.floater&lt;/code&gt; so that the content won’t collide with the dimensions of the &lt;code&gt;button&lt;/code&gt; and instead wraps around it.&lt;/p&gt;
&lt;p&gt;You can remove the &lt;code&gt;demo&lt;/code&gt; attribute from the &lt;code&gt;&amp;lt;closable-surface/&amp;gt;&lt;/code&gt; element to see the final result without the blue box. I’m using a custom element so that it is easy to edit the content without accidentally altering the markup meant for the buoyant button.&lt;/p&gt;
&lt;p&gt;Try removing the title, editing the content, or resizing the window. The content should never collide with the button and always sit at the top corner.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#make-floats-great-again&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title>Colors don&apos;t solve problems</title><link>https://blog.damato.design/posts/colors-dont-solve-problems</link><guid isPermaLink="true">https://blog.damato.design/posts/colors-dont-solve-problems</guid><pubDate>Mon, 11 Jul 2022 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;It’s unfortunate that the first entry at the &lt;a href=&quot;https://lawsofux.com/en/&quot;&gt;Laws of UX&lt;/a&gt; is the “Aesthetic-Usability Effect” which is summarized with the following statement.&lt;/p&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://lawsofux.com/en/aesthetic-usability-effect&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;Users often perceive aesthetically pleasing design as design that’s more usable.&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://lawsofux.com/en/aesthetic-usability-effect&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;Jon Yablonski, Laws of UX&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;p&gt;The source for this law is from an &lt;a href=&quot;https://www.nngroup.com/articles/aesthetic-usability-effect/&quot;&gt;NN/G article&lt;/a&gt; which I find does a much better job summarizing the concept.&lt;/p&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://www.nngroup.com/articles/aesthetic-usability-effect/&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;Users are more tolerant of minor usability issues when they find an interface visually appealing. This aesthetic-usability effect can mask UI problems and can prevent issue discovery during usability testing.&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://www.nngroup.com/articles/aesthetic-usability-effect/&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;Kate Moran, Nielsen Norman Group&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;p&gt;The difference between the two statments is that the former suggests that its good to hide usability problems with garnish. The latter addresses that this is a problem when measuring success accurately. I believe that color is part of that avoidable garnish.&lt;/p&gt;
&lt;h2 id=&quot;full-transparency&quot;&gt;Full transparency&lt;/h2&gt;
&lt;p&gt;I’m color deficient. You might have heard of this as color-blindness however, I am not blind to color. I do not see the world in only black &amp;amp; white. I can see colors, just not as well compared to most people. I can appreciate a good synthwave hot pink most of the time. However I also don’t believe that the world should be black &amp;amp; white. Color provides personality and identity. There’s emotion behind each selection and often relates to an opinion of a piece looking attractive or replusive. It is clearly a driver of some decisions but hardly ones that direct a critical path of usability.&lt;/p&gt;
&lt;h2 id=&quot;art-is-not-design&quot;&gt;Art is not design&lt;/h2&gt;
&lt;p&gt;Art is a freedom of an artist’s expression; an attempt to convey a feeling through their medium. It is commonly an egocentric activity to achieve a desired appearance. This is in contrast to design which is striving for altruism and inclusivity. This is supported through pattern recognition and reusing familiar experiences to achieve a goal. Design systems are the ultimate solution for achieving this cohesive experience; establishing trust between the user and the product. One deviation from past experience could be enough for the user to hesitate on the next step or stop the progress indefinitely.&lt;/p&gt;
&lt;p&gt;In design, form follows function. It means that something should be usable before it is beautiful. In order to do this, we must identify the problem we need to solve. In a qualified user experience practice, this will not begin with designing an interface but with research. Interviews, competitive analysis, user personas, and all the truth finding techniques to paint the best picture of the problem so that you can begin to hypothesize a solution.&lt;/p&gt;
&lt;h2 id=&quot;wirecutting&quot;&gt;Wirecutting&lt;/h2&gt;
&lt;p&gt;After completing a phase of user research, the next task is not jumping into high-fidelity, pixel-perfect mockups. I’ll coin the term “&lt;strong&gt;wirecutting&lt;/strong&gt;” for when a designer cuts out this wireframing step to work on prettier things. Wireframing helps visualize the flow and features expected to support the user’s goals. In this process, it is easy to see when cluttered interfaces appear and the priority of elements reevalutated. These are commonly without color and for good reason. If it doesn’t work in black &amp;amp; white, color isn’t going to help. Putting gold leaf on a turd, is a really shiny turd.&lt;/p&gt;
&lt;p&gt;I believe in a world where wireframes are piped into a tool which creates high-fidelity mockups using the rules and guidance of a design system. Amazingly, this world is here in the form of &lt;a href=&quot;https://uizard.io/&quot;&gt;Uizard&lt;/a&gt;. Using this tool, designers can avoid the nuiances of following the system guidelines and focus on the experience by wireframing. The tool should handle the high-fidelity part of the handoff process. For some folks, this may take some of the fun out of the job. On the other hand, maybe the job was misunderstood in the first place.&lt;/p&gt;
&lt;p&gt;Of course this assumes a design system is well established. So let’s now focus specifically in this area.&lt;/p&gt;
&lt;h2 id=&quot;budget-crayon-box&quot;&gt;Budget crayon box&lt;/h2&gt;
&lt;p&gt;There’s dozens of posts online about how color palettes were created for a design system (&lt;a href=&quot;https://design.lyft.com/re-approaching-color-9e604ba22c88&quot;&gt;Lyft&lt;/a&gt;, &lt;a href=&quot;https://github.blog/2022-06-14-accelerating-github-theme-creation-with-color-tooling/&quot;&gt;Github&lt;/a&gt;, &lt;a href=&quot;https://adobe.design/stories/design-for-scale/reinventing-adobe-spectrum-s-colors&quot;&gt;Adobe&lt;/a&gt;). A great deal of talk about color theory and creating tools to help visualize curves of color for the perfect balance. I cannot deny that resulting palettes are often very beautiful and I often need to use the work of others in order to choose color due to my deficiency. However, &lt;strong&gt;how much of that palette do you really expect to use?&lt;/strong&gt; This is the palette created by Ferdy Christant based on &lt;a href=&quot;https://yeun.github.io/open-color/&quot;&gt;Open Color&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/color-challenged-palette.png&quot; alt=&quot;Large color palette&quot;/&gt;&lt;/p&gt;
&lt;p&gt;That’s a lot of color.&lt;/p&gt;
&lt;p&gt;Let’s first just talk about contrast which is a requirement to make something accessible. If you have several steps of color, I’d guess that many of the colors found within the middle of those steps have trouble being accessible with &lt;em&gt;most&lt;/em&gt; colors in your palette. This is something that &lt;a href=&quot;https://stripe.com/blog/accessible-color-systems&quot;&gt;the Stripe team found&lt;/a&gt; while revisiting color for accessibility. It’s very possible you could omit much from the middle of the palette to support accessible color choice.&lt;/p&gt;
&lt;p&gt;And in &lt;a href=&quot;https://ferdychristant.com/color-for-the-color-challenged-884c7aa04a56&quot;&gt;Ferdy’s post about working with the palette&lt;/a&gt;, there is mention about the lack of accessibility in the palette.&lt;/p&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://ferdychristant.com/color-for-the-color-challenged-884c7aa04a56&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;Open Color does not rank well when it comes to contrast. The root cause here is that we’re paying the price of beauty.&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://ferdychristant.com/color-for-the-color-challenged-884c7aa04a56&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;Ferdy Christant&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;p&gt;You’ll be paying for more than beauty if hit with &lt;a href=&quot;https://www.shrm.org/resourcesandtools/hr-topics/behavioral-competencies/global-and-cultural-effectiveness/pages/record-number-of-lawsuits-filed-over-accessibility-for-people-with-disabilities.aspx&quot;&gt;an accessibility lawsuit&lt;/a&gt;. But Ferdy’s answer is to add &lt;em&gt;more&lt;/em&gt; color; 3 more dark tones to each hue. I don’t agree with this suggestion because trying to choose the right color becomes a challenge when there are so many to choose from (ie., &lt;a href=&quot;https://lawsofux.com/en/hicks-law/&quot;&gt;Hick’s Law&lt;/a&gt;). Limiting the selection drives consistency. I’ll even go so far to say that it enhances creativity because you’ll need to design within constraints which requires out-of-the-(crayon)-box thinking.&lt;/p&gt;
&lt;h2 id=&quot;coloring-outside-the-lines&quot;&gt;Coloring outside the lines&lt;/h2&gt;
&lt;p&gt;Past contrast, let’s now talk about the application of color within an interface. If you look at many modern interface designs today, they tend to follow a 60/30/10 rule. Some sites like &lt;a href=&quot;https://twitter.com/&quot;&gt;Twitter&lt;/a&gt; even let you choose a few colors. This comes from interior design where you choose 3 colors and use them in percentages in your space. This is a loose rule, and &lt;a href=&quot;https://bootcamp.uxdesign.cc/problems-with-the-60-30-10-rule-25206d02bbfd&quot;&gt;opponents of the rule&lt;/a&gt; will call out several factors against it.&lt;/p&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://bootcamp.uxdesign.cc/problems-with-the-60-30-10-rule-25206d02bbfd&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;First, restricting a color palette to only three colors inhibits creative designs. While it prevents overstimulation, exploring more “rebellious” designs make brands stand out from their competitors.&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://bootcamp.uxdesign.cc/problems-with-the-60-30-10-rule-25206d02bbfd&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;Catherine Rasgaitis&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;p&gt;For the purpose of functional product design, I don’t believe we should be striving for creativity in the application of color. Users are expecting familiar and accessible experiences. Painting with all of the colors of the wind will feel like navigating a rainbow hurricane. The limiting of this color helps set expectations as users achieve their goals.&lt;/p&gt;
&lt;p&gt;Even in interior design, the original birth of the rule, it is near impossible to strictly use only three colors. It isn’t realistic. There will be additional hints of other colors outside the chosen selection for elements that make up a room. This is a photo of an actual room in the design systems house.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/ds-house-room.jpg&quot; alt=&quot;Photo of room using balanced color of interior design&quot;/&gt;&lt;/p&gt;
&lt;p&gt;White is a majority, blue is next most prominent, accents are orange-yellow. Importantly there are other colors too! The green plant, the teal footstools, even a rainbow legoset. Admittedly, the rule should probably be something like 55/25/15, which leaves an additional 5% of various colors not covered by the rule where applicable. For user interface design the majority of color will cover the background, the next most important color covers content, and the final most important covers accents that draw the user toward interactivity.&lt;/p&gt;
&lt;p&gt;So for most cases I believe you could probably design the large majority of an interface by having a palette of roughly 10 colors or less.&lt;/p&gt;
&lt;h2 id=&quot;cases-for-more-crayons&quot;&gt;Cases for more crayons&lt;/h2&gt;
&lt;p&gt;An area where more colors are typically introduced are parts of an experience that are meant to indicate status. An error state is frequently shown in red. However, if the text describing the error is too small or thin to distinguish color, it could be missed as an error. Furthermore, the color red is prosperous in China. These are all reasons why we should not rely on color alone to indicate status. I recommend having two forms of status indication; one can be color where cultural sensitivity is considered and then some other pattern to support the status.&lt;/p&gt;
&lt;p&gt;Another area where color is used is to indicate deviations between near identical entities. This can commonly be found in elements like data visualizations (ie., charts) but can also be found when segregating users in a list of contacts. Changes of color here are meant to separate like items making the collection easier to scan.&lt;/p&gt;
&lt;p&gt;I can tell you from experience that I often have difficulty identifying the parts of a data visualization that relies on color to show data &lt;a href=&quot;https://www.nature.com/articles/d41586-021-02696-z&quot;&gt;but don’t take my word for it&lt;/a&gt;. You can imagine how much harder it would be for a blind user to experience. This is again why more emphasis should be given toward presenting the data inclusively, perhaps using a table, and also include a progressive enhancement through a visualization. Putting the color before the data is only helpful for some; let’s consider being help for all. The Carbon folks at IBM have more &lt;a href=&quot;https://medium.com/carbondesign/color-palettes-and-accessibility-features-for-data-visualization-7869f4874fca&quot;&gt;tips to support data visualization for accessibility&lt;/a&gt; and mention more work still needs to be done.&lt;/p&gt;
&lt;h2 id=&quot;finish-with-color&quot;&gt;Finish with color&lt;/h2&gt;
&lt;p&gt;There is a reason why, when you apply stain to a table, the solution you apply is called the “finish”. It happens at the end of the building process. After all the plans are made, the legs cut and fastened, and the top made smooth do you finally apply the coloring. Color can bring the personality to an experience and to call something done. There can be an appropriate time to focus on this work but for the start, keep it simple and use design tokens to support changes for the future. Make color the finish to a usable product.&lt;/p&gt;</content:encoded></item><item><title>Complementary Space</title><link>https://blog.damato.design/posts/complementary-space</link><guid isPermaLink="true">https://blog.damato.design/posts/complementary-space</guid><pubDate>Sun, 16 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;Before &lt;a href=&quot;https://mode.place&quot;&gt;Mise en Mode&lt;/a&gt;, I went on a journey to try to truly understand what it meant to have a design token be “semantic”. The community had a fairly good understanding about what this meant as color, and the benefits that comes from thinking in this way. Text has been perhaps more elusive. Though in recent years we are seeing more and more teams separating the meaning of an “h2” from its visual presentation. Separating the reason why something exists from its style is what semantics is all about.&lt;/p&gt;
&lt;p&gt;What was first &lt;a href=&quot;/posts/spacing-solved&quot;&gt;a blog post here&lt;/a&gt; turned into six months of research now titled &lt;a href=&quot;https://complementary.space/&quot;&gt;Complementary Space&lt;/a&gt; which aimed to rethink space in the same way. What does it mean to apply space somewhere, how would we name those tokens, and most importantly how to convey the concepts of being comfortable or cozy through these tokens.&lt;/p&gt;
&lt;p&gt;This post is meant to revisit the article that I wrote those years ago, share some insights I’ve landed on, and finally to be a memorial as I expect to eventually take the original web page down to reduce cost for all of these domains I have. 😅&lt;/p&gt;
&lt;h2 id=&quot;gestalt-proximity&quot;&gt;Gestalt proximity&lt;/h2&gt;
&lt;p&gt;The first concept to grasp is the purpose of space which is covered by the &lt;a href=&quot;https://www.nngroup.com/articles/gestalt-proximity/&quot;&gt;Gestalt principle of proximity&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The principle of proximity states that items close together are likely to be perceived as part of the same group — sharing similar functionality or traits.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In short, when we apply space somewhere, what we’re doing is conveying a relationship between objects. When there’s more space between items, they are less related than items that are more closely related.&lt;/p&gt;
&lt;p&gt;This means that the value that we assign to spacing properties is describing a relationship. There’s two kinds of relationships that we see, parent-child and sibling relations. Parent-child relationships tend to have a larger amount of space, or in terms of relationships, are slightly more distant than siblings. This is a common visual paradigm, where the padding around the card holding the children inside is larger than the gaps between those children (ie., siblings).&lt;/p&gt;
&lt;h2 id=&quot;periscope&quot;&gt;Periscope&lt;/h2&gt;
&lt;p&gt;Historically, we’d use something like a T-shirt scale to say how much space are between the objects. However, as I’ve said before, &lt;a href=&quot;/posts/truly-semantic&quot;&gt;scales aren’t semantic&lt;/a&gt;. It isn’t clear where any of these tokens are meant to go in the experience. It’s subjective.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/non-semantic-tokens.png&quot; alt=&quot;Button color is semantic, space-4 is not&quot;/&gt;&lt;/p&gt;
&lt;p&gt;What I landed on after much development is to &lt;strong&gt;have the scope describe the density of a region, not the tokens&lt;/strong&gt;. To get a better understanding of the idea, let’s watch a moment from the TV show MacGyver. Specifically this clip from episode called “Hell Week”.&lt;/p&gt;
&lt;iframe width=&quot;100%&quot; style=&quot;aspect-ratio: 16/9&quot; src=&quot;https://www.youtube.com/embed/oPQ-5H_AU18?si=ySZieleRVeFpASIh&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;In the clip, the male student is competing in a contest which is meant to keep other students from entering their dorm. Each student devises a way to keep the door from opening but all have some solution that allows entry. This student’s idea was to make a miniture version of the room. Everything is copied in detail so that when you look through the door’s eyehole, you see the miniture but it looks like a normal size room.&lt;/p&gt;
&lt;p&gt;The point of this example is that trying to determine the space between objects without knowing the frame of reference makes it so those distances are visually equal. Certainly, if we are inside of the room we can see, and more importantly &lt;em&gt;measure&lt;/em&gt;, the distance between the bed and desk. When we do this, we can immediately tell that the distance between these items in the life-sized room is much larger than the model. But through the eye-hole you can’t because the frame or reference is gone. Everything is proportional. This is how scale models work. You measure the life-size objects, and then apply some ratio to scale them up or down. Through different lenses these can appear the same but in the larger environment actually be different sizes.&lt;/p&gt;
&lt;p&gt;Another way of thinking about this is the distance between you and your front door in comparison to the distance between you and the nearest ocean. The nearest ocean is probably very “far” for most people in comparison to their front door. Now, think about the distance between you and the nearest ocean, and the distance between you and the moon. Suddenly the distance between you and the ocean isn’t far at all. Changing the frame of reference is changing what it means to be far.&lt;/p&gt;
&lt;p&gt;The point here is that we can change what it means to be “far” by changing the scope. And because our goal is to semantically define what it means to be far, all we need to do is have different “scopes” that express different kinds of far. More importantly, when I say “far”, I really mean space.&lt;/p&gt;
&lt;p&gt;In the following image, I’ve made a component that could either represent the entire page or a card within the page.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/page-or-card.jpeg&quot; alt=&quot;Is it a page or is it a card?&quot;/&gt;&lt;/p&gt;
&lt;p&gt;I use the same base composition for both of these things. On the right, the smaller components found within the larger one are really just scaled down versions of the larger one. Certainly, we see things like typography scaled down, but we also see the space scaled down too.&lt;/p&gt;
&lt;p&gt;In this way, we don’t see the page as a whole. Instead we zoom into individual scopes of the composition and then decide how dense that region should be. Generally the deeper we go, the more dense the composition is expected to be.&lt;/p&gt;
&lt;h2 id=&quot;what-are-the-tokens&quot;&gt;What are the tokens?&lt;/h2&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;In the original article, I recommend having two tokens “near” and “away” to signify close and far relationships. Since writing this article, I’ve found that even this decision can be confusing. While in later recommendations and even examples, I suggest having a single token. &lt;a href=&quot;https://system.damato.design&quot;&gt;In practice&lt;/a&gt;, I’ve renamed these tokens to “padding” and “gap” which represent the parent-child and sibling relationships through space more clearly.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;In all of this research, it was important to me that I could land at a similar outcome to what Nathan Curtis had written about in &lt;a href=&quot;https://medium.com/eightshapes-llc/space-in-design-systems-188bcbae0d62&quot;&gt;his work on spacing tokens&lt;/a&gt; back many years prior but to have this new way of understanding space. Here’s his approach from the article and the complementary approach side-by-side.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/cards-nathan-complementary.png&quot; alt=&quot;Clean card, Nathan&apos;s approach, and Complementary Space&quot;/&gt;&lt;/p&gt;
&lt;p&gt;In Nathan’s approach, you’ll see that each space token describes composition of the space and its amount. Inset means it goes around content, stack means it goes between elements on adjacent sides, and gap means it goes between on all sides. In this way, there’s lots of decisions that must happen at each location where space is going to exist that also depend on the composition of the elements.&lt;/p&gt;
&lt;p&gt;In Complementary Space you’ll see that there is a single token placed for every location we expect to represent some amount of space. This immediately reduces decision making because there is only one token to choose. This means that the only decision that a person needs to make is the “scope” of the content. In other words, am I expecting to reduce the context down to a lower level of hierarchy than the parent above. Where these scopes occur are represented by the dotted borders surrounding regions of the card in the example.&lt;/p&gt;
&lt;h2 id=&quot;what-else-do-i-need&quot;&gt;What else do I need?&lt;/h2&gt;
&lt;p&gt;Below is a interactive demo of the approach, showing how we can make a region more dense by adding the &lt;code&gt;data-density-shift&lt;/code&gt; attribute. See how there are several different amounts of space being applied while using very few differently named tokens, in this case &lt;code&gt;--space-near&lt;/code&gt; and &lt;code&gt;--space-away&lt;/code&gt; from the original implementation.&lt;/p&gt;
&lt;iframe height=&quot;550&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;complementary.space&quot; src=&quot;https://codepen.io/fauxserious/embed/dyJgzBM?default-tab=result&quot; frameborder=&quot;no&quot; loading=&quot;lazy&quot; allowtransparency=&quot;true&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/fauxserious/pen/dyJgzBM&quot;&gt;complementary.space&lt;/a&gt; by Donnie D’Amato (&lt;a href=&quot;https://codepen.io/fauxserious&quot;&gt;@fauxserious&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;Again, this isn’t entirely needed as demostrated from the image just before but representing &lt;code&gt;padding&lt;/code&gt; and &lt;code&gt;gap&lt;/code&gt; as describing relationships seems to describe the purpose more than a single space token.&lt;/p&gt;
&lt;p&gt;Either with one token or two, this works by compounding identical selectors. Assuming that the way something becomes more dense is by being identified with &lt;code&gt;data-density-shift&lt;/code&gt;, this is how you’d create the levels:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;data-density-shift&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;] {...}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;data-density-shift&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;] [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;data-density-shift&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;] {...}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;data-density-shift&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;] [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;data-density-shift&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;] [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;data-density-shift&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;] {...}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, we duplicate the &lt;code&gt;data-density-shift&lt;/code&gt; attribute selector which shows how deep the region is related to other density shifts. While you could have more control by explicitly giving each shift a number related to depth, this brings a subjective decision in an otherwise binary decision of “should this be more dense that the region above?” This also brings more care to the hierarchy of the page. Things that are less dense are more spread out and unrelated sections of content are clearer than if they were composed without these considerations.&lt;/p&gt;
&lt;p&gt;Within each level, we expect the spacing values to decrease, making compositions appear more dense. In the CodePen, I create a few Sass functions to help generate the scale based on the number of levels. In the code below I’ve updated to use &lt;code&gt;padding&lt;/code&gt; and &lt;code&gt;gap&lt;/code&gt; instead of the earlier &lt;code&gt;near&lt;/code&gt; and &lt;code&gt;away&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;scss&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;$attr-sel&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;[data-density-shift]&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;$levels&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;/* including body */&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:var(--astro-code-token-comment)&quot;&gt;/* Fibonacci Sequence */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;@function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; fib&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;($n) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  @return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;($n &amp;lt;= &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; fib&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;($n &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; fib&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;($n &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;@mixin&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; vars&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;($n) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  --padding&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    #{&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;fib&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;($n &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1)} &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--density&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  )&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  --gap&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    #{&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;fib&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;($n)} &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--density&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  )&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;@for&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; $i &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; through&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; $levels {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  $nest-sel&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;($i == 1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;body&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; selector-nest&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;($nest-sel&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; $attr-sel))&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-color-text)&quot;&gt;  #{$nest-sel} {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    @include&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; vars&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;($levels &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; $i);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You might also notice that I’ve replaced the usage of &lt;code&gt;rem&lt;/code&gt; with &lt;code&gt;px&lt;/code&gt; in the code above. &lt;a href=&quot;/posts/font-size-dimensions/&quot;&gt;This is a separate topic&lt;/a&gt; but in short, if the user increases the font size, this is meant to help with readability and the user isn’t meaning to “read” space. Therefore, using units unrelated to typography are preferred.&lt;/p&gt;
&lt;p&gt;Speaking of values, this is an area where you might want to explore even further. For example, on touch devices, you might consider having more space than on devices where a pointer is used. This is to increase the target area of interactive elements and make them slightly easier to interact with than using a finer pointing device. Importantly, this is not the difference between “mobile” and “desktop” &lt;a href=&quot;https://spectrum.adobe.com/page/platform-scale/&quot;&gt;as some might have you believe&lt;/a&gt;. The reason why we should be making space larger is for interactive targetting, not because something is considered mobile. Since this something that should affect the experience globally, this is a matter of updating the density under a media query.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-keyword)&quot;&gt;@media&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (any-pointer&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; coarse) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;    :root&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        --density&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt; /* something a bit larger */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I recommend reading &lt;a href=&quot;https://css-tricks.com/interaction-media-features-and-their-potential-for-incorrect-assumptions/&quot;&gt;this post at CSS-Tricks&lt;/a&gt; about interaction media queries for further considerations.&lt;/p&gt;
&lt;h2 id=&quot;avoiding-size-variants&quot;&gt;Avoiding size variants&lt;/h2&gt;
&lt;p&gt;A large benefit of the scope-based approach is that size variants for your system are no longer meticiously defined. The size of an element is determined by the context it is placed within. In other words, if the button is meant to be smaller, place the button in a region meant to convey a higher density.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/button-scoped-density.jpeg&quot; alt=&quot;Button size determined by the scope&quot;/&gt;&lt;/p&gt;
&lt;p&gt;This is assuming that other cosmetic properties of the button are also determined by the density, such as font-size.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://system.damato.design/?path=/docs/foundations-density--docs&quot;&gt;An example at my design system&lt;/a&gt; illustrates this in code in the following way where &lt;code&gt;denser&lt;/code&gt; causes the scope to increase in density (ie., space becomes smaller) and can be added to any element:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;box.div&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; denser&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; gap&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; priority&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;primary&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;box.div&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; denser&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; gap&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; priority&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;primary&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;box.div&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;box.div&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because the size of the gap is wholly determined by the surrounding scope, &lt;code&gt;gap&lt;/code&gt; becomes a flag that merely indicates if space should exist between the children at all.&lt;/p&gt;
&lt;p&gt;While this does create the ability to have more levels of space than you should ever use, I recommend having 3 to start. The highest level designed to support marketing pages, the next level designed to support general productivity dashboards, and the last level to help with the composition of cards and other focused regions. This assumes that you are representing &lt;code&gt;padding&lt;/code&gt; and &lt;code&gt;gap&lt;/code&gt; as tokens. If not, you might require more levels to accurately describe different kinds of space from scope alone.&lt;/p&gt;
&lt;h2 id=&quot;when-will-you-be-ready&quot;&gt;When will you be ready?&lt;/h2&gt;
&lt;p&gt;The reality is that &lt;em&gt;we are still teaching teams semantic color&lt;/em&gt;, let alone semantic space. People continue to hard code values into places where they just can’t be bothered to do the right thing. Until we change the mindset of the industry, we’ll be stuck doing things the old-fashioned way, wondering why it’s so hard to make new expressions of our experiences.&lt;/p&gt;
&lt;p&gt;So, instead of trying to implement in your company’s design system. I recommend trying to implement into your own personal projects. That way, the understanding of how everything works doesn’t need to go beyond you. Give it a shot, and let me know how it goes? Let’s make space complementary. 🤝&lt;/p&gt;</content:encoded></item><item><title>CSS Only Contrast</title><link>https://blog.damato.design/posts/css-only-contrast</link><guid isPermaLink="true">https://blog.damato.design/posts/css-only-contrast</guid><pubDate>Wed, 04 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;I think many of us who work with CSS and accessibility have been looking for a solution that helps provide the right amount of contrast for a given color. It’s floated around as a function within different CSS color specifications, currently found as &lt;a href=&quot;https://drafts.csswg.org/css-color-5/#contrast-color&quot;&gt;&lt;code&gt;contrast-color()&lt;/code&gt; in CSS Color Module Level 5&lt;/a&gt; with the following syntax:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;background: var(--color);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;color: contrast-color(var(--color));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unfortunately, this isn’t available in any browser and there’s no references found for it in MDN or caniuse. So, do we just keep waiting? Maybe not!&lt;/p&gt;
&lt;h2 id=&quot;prior-art&quot;&gt;Prior art&lt;/h2&gt;
&lt;p&gt;Over 5 years ago, there was &lt;a href=&quot;https://css-tricks.com/css-variables-calc-rgb-enforcing-high-contrast-colors/&quot;&gt;a post on CSS Tricks&lt;/a&gt; that began to poke at this problem. &lt;a href=&quot;https://joshuabader.com/&quot;&gt;Josh Bader&lt;/a&gt; outlined a method that takes the channels of an RGB color and combines the values into a luminance value to be reassigned into a new RGB color.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;:root&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  --red&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 28&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  --green&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 150&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  --blue&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 130&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-color-text)&quot;&gt;  --accessible-channel&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;      (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--red) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 299) +&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--green) * 587&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;) +&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;          (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(--blue) * 114)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        ) / 1000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      ) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; 128&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    ) * &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;1000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  --accessible-color&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; rgb&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--accessible-channel)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--accessible-channel)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--accessible-channel)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  )&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;I’ve updated the example a bit to demonstrate that the calculations are trying to determine the channels for the color, not the color directly.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;The problem with this approach is that you needed to know the amount of each channel such that it could be combined together. This made it tedious to define a color because it’s uncommon to have to set color channels individually, especially when we begin to use variables and tokens which are curated by folks that aren’t close to the code.&lt;/p&gt;
&lt;p&gt;Luckily, we do have some modern CSS that can help with this and get us much closer to a good developer experience with only CSS.&lt;/p&gt;
&lt;h2 id=&quot;relative-color-syntax&quot;&gt;Relative color syntax&lt;/h2&gt;
&lt;p&gt;The new CSS Relative Color Syntax &lt;a href=&quot;https://caniuse.com/css-relative-colors&quot;&gt;part of baseline 2024&lt;/a&gt; allows you to get the individual channels of a color function and mutate the output. Here’s a simple example:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;background: rgb(from var(--color) r r r);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can identify relative color with the &lt;code&gt;from&lt;/code&gt; keyword in the color function. What this would do is take the red channel of the &lt;code&gt;var(--color)&lt;/code&gt; and assign that value to the R, G, and B channels of a new color. In other words, using the red channel of the given color to make a new grayscale color. You should see that this is the missing piece to Josh’s idea, so here’s how we’re going to put it together.&lt;/p&gt;
&lt;p&gt;First, we’re going to simplify Josh’s implementation a bit. Here’s the calculation we’re going to use instead:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;clamp(0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (((r &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; .299) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;g&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; .587) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;b&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; .114)) - 128) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; -1000&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; 255);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Doing it this way omits the &lt;code&gt;/ 1000&lt;/code&gt; by using decimals for the magic luminance numbers. This will return the amount for each RGB channel to be either black or white. This means we’d need to duplicate the same calculation a few times in the relative color function.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;rgb(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    from var(--color)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    clamp(0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (((r &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; .299) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;g&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; .587) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;b&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; .114)) - 128) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; -1000&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; 255)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    clamp(0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (((r &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; .299) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;g&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; .587) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;b&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; .114)) - 128) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; -1000&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; 255)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    clamp(0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (((r &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; .299) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;g&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; .587) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;b&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; .114)) - 128) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; -1000&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; 255)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We need to duplicate this because the relative color syntax must return a color, not an individual number, so we need to do the same calculation at each channel. It’s sort of like doing the procedure all in a single function but as a requirement due to how relative colors work. This makes the code a little messy, so instead I’ll recommend registering a CSS custom property that can be reused:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-keyword)&quot;&gt;@property&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; --channel {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    syntax: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    inherits: false;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;    initial-value&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;: clamp(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        (((r &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; .299) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;g&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; .587) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;b&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; .114)) - 128) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; -1000&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        255&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that we have that, we can finally use the &lt;code&gt;--channel&lt;/code&gt; variable within the relative color syntax to create the new color:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.color&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --color&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; #bada55&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    background&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--color)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    color&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; rgb&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        from &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--color)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--channel)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--channel)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--channel)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    )&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You could also opt to hide the relative syntax in another variable so your peers don’t need to remember the syntax and can use a custom property instead:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-comment)&quot;&gt;/* tokens */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;:root&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --color&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; #bada55&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --contrast-color&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; rgb&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        from &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--color)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--channel)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--channel)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--channel)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    )&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-comment)&quot;&gt;/* app */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.color&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    background&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--color)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    color&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--contrast-color)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Check out the codepen below which includes a color picker and notice how the text changes color from black to white depending on your chosen color:&lt;/p&gt;
&lt;iframe height=&quot;500&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;CSS only WCAG contrast color&quot; src=&quot;https://codepen.io/fauxserious/embed/ZYGBgYQ?default-tab=css%2Cresult&quot; frameborder=&quot;no&quot; loading=&quot;lazy&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/fauxserious/pen/ZYGBgYQ&quot;&gt;
CSS only WCAG contrast color&lt;/a&gt; by Donnie D’Amato (&lt;a href=&quot;https://codepen.io/fauxserious&quot;&gt;@fauxserious&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;&lt;strong&gt;EDIT (2025-06-04):&lt;/strong&gt; After sharing the approach &lt;a href=&quot;https://matthewstrom.com/&quot;&gt;Matt Ström-Awn&lt;/a&gt; &lt;a href=&quot;https://codepen.io/ilikescience/pen/azOpOqX&quot;&gt;made some improvements&lt;/a&gt;. Here’s a quote from the thread in the Design System’s Slack:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;super cool! you sparked my curiosity; i know that the wcag contrast algorithm uses xyz’s ‘y’ value as its definition of relative luminosity; so if you do the relative color in xyz instead of rgb it simplifies the math a bit.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;color: color(from var(--color) xyz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; round(up&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; min(1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; max(0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.18&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; - y)))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; round(up&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; min(1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; max(0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.18&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; - y)))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; round(up&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; min(1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; max(0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.18&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; - y)))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;Admittedly, I’m not good with color math but &lt;a href=&quot;https://matthewstrom.com/writing/generating-color-palettes/&quot;&gt;I know Matt is&lt;/a&gt; so I trust this is a better approach.&lt;/p&gt;</content:encoded></item><item><title>Defending Tailwind</title><link>https://blog.damato.design/posts/defending-tailwind</link><guid isPermaLink="true">https://blog.damato.design/posts/defending-tailwind</guid><pubDate>Thu, 06 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;If you told me 2 years ago that I was going to write this post, I would have scoffed at the thought. But after a deeper think related to the current state of affairs when it comes to development today, I get it.&lt;/p&gt;
&lt;p&gt;The thumbnail used to promote the &lt;a href=&quot;https://www.buzzsprout.com/1958356/episodes/14701631-15-donnie-d-amato-what-s-a-component&quot;&gt;Code &amp;amp; Pixels&lt;/a&gt; podcast says it all.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/codepixels-thumbnail.jpg&quot; alt=&quot;Me, with the text &amp;#34;I don&apos;t like Tailwind&amp;#34;&quot;/&gt;&lt;/p&gt;
&lt;p&gt;I’m very confident that there will never be a time where I will consciously choose Tailwind to style my work. I have too much experience working with CSS to need it. But it wasn’t until a few years ago that I had a wake up call about the gap between my skill and the skills of over developers around me.&lt;/p&gt;
&lt;h2 id=&quot;hiring-greatness&quot;&gt;Hiring greatness&lt;/h2&gt;
&lt;p&gt;When I worked for Compass, I was a part of practically every frontend engineering hire starting at my 3rd week of employment there. I’ve attributed it to the person asking me the CSS question disclosing that it took him an entire week to do what I did in 20 minutes during the interview. He had nothing left to ask after blowing away any doubt I’d be able to do the job.&lt;/p&gt;
&lt;p&gt;In that time, we created what I can only describe as the best frontend engineering team I’ll probably ever see. Every person with the title frontend engineer was solid in CSS. No problems centering elements, boxes aligned nicely, and responsive design was at the top of everyone’s mind. I was still involved to kickstart newer projects with complex layout needs. The use of CSS grid on the &lt;a href=&quot;https://www.compass.com/listing/44-prospect-park-west-unit-a1-brooklyn-ny-11215/1774010098596006345/&quot;&gt;listing page&lt;/a&gt; is still largely of my doing, now over 6 years old.&lt;/p&gt;
&lt;p&gt;I got a rude awakening when leaving Compass, when new my senior director told me that I was an outlier. I didn’t know how true that was until more recently.&lt;/p&gt;
&lt;h2 id=&quot;more-important&quot;&gt;More important&lt;/h2&gt;
&lt;p&gt;What I’m realizing now is there’s more of a focus on just getting it done. An engineer gets a design thrown over the fence and their job is to “just do it”. The organization wants to get it done as quickly as possible. This means there’s a lack of care in things that are deprioritized. When the majority of full stack engineers are trying to wrangle CSS, it isn’t important to them how to organize that CSS. They just want to set this color on that element and move on to more important things.&lt;/p&gt;
&lt;p&gt;That’s where Tailwind comes in.&lt;/p&gt;
&lt;h2 id=&quot;whats-good&quot;&gt;What’s “good”&lt;/h2&gt;
&lt;p&gt;There’s two “good” things about Tailwind which I’ll address separately in paragraphs below:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You don’t need to think of a name for the thing that needs styles.&lt;/li&gt;
&lt;li&gt;There’s no context switching between the file where you write styles to the file where those styles are being applied.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I can definitely agree that naming something &lt;code&gt;.wrapper&lt;/code&gt; is awful. It gives no context to where it is or what it is doing. It’s often a challenge to think of a good name to provide a hook for these styles. Especially styles that are being used once and in a project that might have multiple teams trying to name their &lt;code&gt;.card&lt;/code&gt; and having things conflict. Going the small step of namespacing the class names manually is too much forethought, so we’d rather complain that CSS is broken.&lt;/p&gt;
&lt;p&gt;Should we assume that a good engineer would have good naming skills? We could, but in most facets of programming you don’t need to because of scope. There’s countless &lt;code&gt;main()&lt;/code&gt; calls out there. The feature of CSS being global causes headaches for folks looking for scoped styles. Overrides bleed into unintended places and it becomes a big hassle in the way of more important work.&lt;/p&gt;
&lt;p&gt;This is a reason why libraries like &lt;a href=&quot;https://styled-components.com/&quot;&gt;Styled Components&lt;/a&gt; got so popular. The component you created in React was created from declaring styles.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; Title&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; styled&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  font-size: 1.5em;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  text-align: center;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  color: #BF4F74;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Boom! You’ve created a component and added the styles in one shot. And because of the hashed classes underneath, conflicts are avoided. I actually agree with this approach. This is a component-first way of thinking. The reuse is in the components, not in the styles. It’s a lot of the reason why I adopted Shadow DOM early on. Tailwind does this too, just with more native syntax in HTML.&lt;/p&gt;
&lt;p&gt;This makes way into the second point of context switching. Historically, you’d have to create something in your HTML structure for you to then hook into with CSS styles in a separate file. You’d have to remember what that name was in order to style it. On top of this, you’d also have to switch to the rendered result to see what the effect was. There’s a lot of screens to switch in between just to see what’s happening. It makes a lot of sense to reduce that by writing everything in a single file.&lt;/p&gt;
&lt;p&gt;I have empathy for this since recently writing Astro components. All the code for an Astro component is in a single &lt;code&gt;.astro&lt;/code&gt; file. I’ve noticed that I tend to write a few lines of HTML, maybe even less of JS, but the large majority of the file is CSS. It’s clear to me that much of the time spent coding in frameworks is CSS and engineers are going to want to reduce that time.&lt;/p&gt;
&lt;p&gt;With Tailwind, a person can write the HTML and CSS in one shot. Is it a lot of HTML now? Most likely, but we can tuck that away in the code editor. The organization of styles is wired to the organization of the HTML. It’s a two-for-one special and that must be better, right?&lt;/p&gt;
&lt;h2 id=&quot;whats-bad&quot;&gt;What’s bad&lt;/h2&gt;
&lt;p&gt;Responsibility and scale.&lt;/p&gt;
&lt;p&gt;The naming convention that Tailwind uses forces the engineer to be in charge of when a CSS value gets applied. If you want to have a theming system that can change between different values, what &lt;code&gt;color-red-500&lt;/code&gt; means can’t change, it must continue to be a red. It’s entirely possible that the &lt;code&gt;color-red-500&lt;/code&gt; is not appropriate for the new context, and some engineer must go in and add new logic with some new class name.&lt;/p&gt;
&lt;p&gt;I don’t know about other folks, but I don’t want my role to be reduced to responding to every call for a new cosmetic change in the interface. Adding new logic to juggle these classes. I want the folks who ask for the change to do it themselves. Tailwind’s naming convention won’t let you do that. Maybe this is job security, but its also looming technical debt.&lt;/p&gt;
&lt;p&gt;If you did want to have flexibility with some class naming convention, classes would need to be named &lt;a href=&quot;/posts/truly-semantic&quot;&gt;semantically&lt;/a&gt;. As in, what the purpose of the thing is, not how it is styled since that could change over time. The purpose of the thing doesn’t change. Unfortunately, creating custom names is precisely what &lt;a href=&quot;https://v3.tailwindcss.com/docs/reusing-styles#avoiding-premature-abstraction&quot;&gt;Tailwind recommends to avoid&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Need a small utility to nudge something? That’s a deeper problem with either the design or the engineering of the component. That should be addressed with revisiting the composition, not by adding a utility to pummel the style into submission. But we don’t have time to discuss that. Add the utility, it’s what they are there for. We’ll fix it &lt;del&gt;later&lt;/del&gt; never.&lt;/p&gt;
&lt;p&gt;The fact is folks who use Tailwind aren’t thinking about responsibility and scale in this way. They are thinking how can I push this out as fast as possible. And Tailwind is great for that. Educating on best practices is always hard. In the year 2025, I still see people struggling with responsive design techniques. So setting &lt;code&gt;color-red-500&lt;/code&gt; permanently isn’t going away tomorrow and the marketing of Tailwind is going to make that exceptionally difficult. We can hope that folks realize this sooner rather than later.&lt;/p&gt;
&lt;p&gt;But I guess you could just have AI rewrite it now so no problemo?&lt;/p&gt;</content:encoded></item><item><title>Design Attractors</title><link>https://blog.damato.design/posts/design-attractors</link><guid isPermaLink="true">https://blog.damato.design/posts/design-attractors</guid><pubDate>Fri, 26 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;This week I tuned into &lt;a href=&quot;https://bencallahan.com/the-question&quot;&gt;The Question by Ben Callahan&lt;/a&gt;, co-hosted by &lt;a href=&quot;http://www.artist-developer.com/&quot;&gt;Natalya Shelburne&lt;/a&gt;. During the chat I shared one of my patented hot takes: the design system specialist role will eventually disappear. Of course, if that’s true, it doesn’t bode well for me or for the rest of us in the meeting. Design systems are what we do. The rebuttal in the chat was strong: systems are becoming more complex than ever, and organizations need our expertise to make sense of it all.&lt;/p&gt;
&lt;h2 id=&quot;our-role-today&quot;&gt;Our role today&lt;/h2&gt;
&lt;p&gt;Much of our work today is about &lt;em&gt;agreement&lt;/em&gt; in an organization. In fact, when people ask me to define a design system, I often reply with that single word: agreement. The resources we maintain represent those agreements. A design system maintainer doesn’t really care what color a button is. They care about getting the organization to agree on which color it should be.&lt;/p&gt;
&lt;p&gt;The complexity of our role lies in managing expectations before these agreements are made: the expectations of users who will one day interact with the products, and the expectations of peers who are building the next version of those products. When marketing says they need a carousel, the challenge isn’t the carousel itself, it’s gathering requirements across humans: our users and our peers. That process produces tokens, components, and guidelines. Abstractly, though, those are just agreements.&lt;/p&gt;
&lt;h2 id=&quot;chaos-theory&quot;&gt;Chaos theory&lt;/h2&gt;
&lt;p&gt;From &lt;a href=&quot;https://en.wikipedia.org/wiki/Chaos_theory&quot;&gt;Wikipedia&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Chaos theory states that within the apparent randomness of chaotic complex systems, there are underlying patterns, interconnection, constant feedback loops, repetition, self-similarity, fractals and self-organization.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I see design systems as subjects of chaos theory. The complexity comes from infinite, undefined human requirements that maintainers must observe and distill into deliverables. But it’s that last word &lt;strong&gt;self-organization&lt;/strong&gt; that feels like the next step.&lt;/p&gt;
&lt;p&gt;The knee-jerk reaction is to say a self-organized design system is impossible. Under traditional methods, that’s probably true. After all, this role exists precisely because someone has to deliberately gather requirements and deliver resources. However, I believe we’ve already answered many of these requirements. Much of the knowledge is common and repeatedly applied. We’ve already settled on many truths about building design systems, whether we recognize it or not.&lt;/p&gt;
&lt;h2 id=&quot;the-perfect-button&quot;&gt;The perfect button&lt;/h2&gt;
&lt;p&gt;What is wrong with this button?&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blue-button.jpeg&quot; alt=&quot;Blue button with teal text&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Most practitioners would agree the background and text colors lack sufficient contrast. &lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html&quot;&gt;According to the WCAG&lt;/a&gt; the ratio should be at least 4.5:1. We’ve landed on a stable configuration for the relationship between a button’s background and text. We now expect all buttons to meet this contrast ratio in order to be useful.&lt;/p&gt;
&lt;p&gt;This is what I call a &lt;strong&gt;design attractor&lt;/strong&gt;. In &lt;a href=&quot;https://fiveable.me/chaos-theory/unit-3/types-attractors/study-guide/THSUlEJENrwcpgvX&quot;&gt;chaos theory&lt;/a&gt;, an attractor is the stable state toward which a system evolves over time. In design, for a button to be a button, it must also be interactive. This is a design attractor. From there, users expect some visual treatment to distinguish it from non-interactive elements. Exactly what that treatment looks like depends on the local agreements within an organization, but once settled, that’s another design attractor.&lt;/p&gt;
&lt;p&gt;This is why I believe in &lt;a href=&quot;https://bradfrost.com/blog/post/a-global-design-system/&quot;&gt;Brad Frost’s Global Design System&lt;/a&gt; idea. We know what a button is supposed to be and do. So why are we constantly recreating buttons with that knowledge? Functionally, we’ve already converged toward the answers, toward design attractors. These are the stable solutions that emerge as the natural equilibrium of usability, accessibility, and implementation constraints.&lt;/p&gt;
&lt;h2 id=&quot;in-the-world-of-ai&quot;&gt;In the world of AI&lt;/h2&gt;
&lt;p&gt;AI tools today can take a prompt and deliver mediocre user experiences. But how can they even do that? Because they too have developed design attractors, including ones that we haven’t yet defined. They “know” what a button is and can reference those rules to produce another that meets expectations. While they can’t yet replicate the exact button from your specific design system, we’re not far off. We didn’t need to explain the concept of a button to these systems. They figured it out.&lt;/p&gt;
&lt;p&gt;If they can do that, why couldn’t they learn more from additional information? And by “information,” I mean &lt;em&gt;requirements&lt;/em&gt;. Today, AI gathers requirements for individual tasks. Tomorrow, it could gather requirements for entire organizations and deliver outputs that meet shared human expectations.&lt;/p&gt;
&lt;p&gt;The largest argument here is one of &lt;em&gt;expression&lt;/em&gt;. This is why the Global Design System idea is hard to grasp. The button at Home Depot isn’t the same as the button at Visa, or so it seems. In reality, they’re functionally the same button. The difference is in local agreements: Home Depot’s cosmetic style versus Visa’s. Even those stylistic choices still follow the same design attractors. Remember the contrast ratio requirement? Both Home Depot and Visa buttons differ in appearance but follow the same underlying rules.&lt;/p&gt;
&lt;p&gt;I believe there’s a world where AI synthesizes design attractors at scale, allowing a design system to self-organize within an organization. A designer would contribute simply by designing. That contribution would influence the larger system and shift the design attractor slightly. If someone introduced a low-contrast button, it would have little impact against the weight of prior knowledge of higher-contrast buttons. Bad behavior contributes very little; good behavior contributes naturally toward the attractor.&lt;/p&gt;
&lt;p&gt;A person shouldn’t need to look up guidelines, tokens, or components to work. Those resources should be embedded in their context. And even if an experience is claimed to be novel, we’re never truly starting from scratch. Styles themselves would be learned and refined over time, converging toward agreement as the system internalizes how the organization operates.&lt;/p&gt;
&lt;h2 id=&quot;where-are-the-people&quot;&gt;Where are the people?&lt;/h2&gt;
&lt;p&gt;What keeps our roles relevant today is AI’s lack of accuracy. We’ve all seen &lt;a href=&quot;https://www.404media.co/the-software-engineers-paid-to-fix-vibe-coded-messes/&quot;&gt;reports of “vibe-coded” work that humans must revisit&lt;/a&gt;. And with the complexity of managing expectations across design and development, any inaccuracy erodes trust. Lose trust, and the system collapses. Our roles exist because organizations trust us to deliver accurate agreements, no matter how messy the human dynamics.&lt;/p&gt;
&lt;p&gt;But we should be prepared for a future where AI becomes trustworthy enough to take on more of this work. Certainly, there are ethical concerns far beyond design systems. But for now, it’s enough to recognize that design attractors exist and we can either harness them ourselves, or let the machines do it for us.&lt;/p&gt;
&lt;p&gt;What will you decide?&lt;/p&gt;</content:encoded></item><item><title>Done with components</title><link>https://blog.damato.design/posts/done-with-components</link><guid isPermaLink="true">https://blog.damato.design/posts/done-with-components</guid><pubDate>Wed, 30 Apr 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;I’m done building components. 🙅&lt;/p&gt;
&lt;p&gt;This feeling was already strong for me. Teams are always in need of their own components for experiences that are unique to the platform. That means they need their own infrastructure for component development. These get built in isolation and don’t have the same level of communication that components in the core design system would have. This is something that a design system can’t stop and really shouldn’t stop.&lt;/p&gt;
&lt;p&gt;That’s why I see a future in the “component marketplace”, where all components are meant to be built which gives visibility not only across teams who want to use existing resources other teams have built but for leadership to clearly understand the landscape of their design language. Its consistency or its lack thereof. This would require some sort of desire for teams to start building on the marketplace. Maybe it gives them auto-docs or a testing harness that is easy to use. Maybe it gives them metrics into how people are using their stuff. Maybe there’s some other attraction that I’m overlooking.&lt;/p&gt;
&lt;p&gt;I know what you’re thinking, this is how we get a dozen different buttons across the organization because anyone can put them there. And that’s the point. If the organization wants all of those buttons, they can have them. And that’s often how a design system starts. We do the classic “button audit” find that there’s 12 different kinds and the design system team is born. But what if that audit was not a moment in time, but a dashboard? What if your design leadership could open it up at any time and decide if this was acceptable?&lt;/p&gt;
&lt;p&gt;I think this visibility and access would clearly describe the behavior of design leadership. Organizations that want consistency would take actionable steps against the resources found in the marketplace, potentially sending out their design systems team to work with those creators for alignment. On the flip side, organizations that don’t care will continue not caring and it’ll show very clearly. Until then, design leadership can blissfully hide behind not having enough resources to do the audit and no one can be sure there are inconsistencies at all. 🫣&lt;/p&gt;
&lt;h2 id=&quot;the-last-straw&quot;&gt;The last straw&lt;/h2&gt;
&lt;p&gt;This past weekend, my disdain for building components was solidified. I realized what a definitive difference is between a design system and a component library was.&lt;/p&gt;
&lt;p&gt;I’ve always said that a design system is a matter of agreement. It’s what the organization collectively agrees should be the overall strategy when it comes to design. However, what happens when that agreement is &lt;em&gt;objectively&lt;/em&gt; wrong? This can be compounded by larger organizations proudly displaying poor choices. Those choices are replicated and then defended by the bandwagon effect. This results in a component library. They’re just components based on feelings. People want components, so they get components.&lt;/p&gt;
&lt;p&gt;Does a design system have a component library? Sure, but the difference is the thoughtfulness of their inclusion. Is it easy to make your own button? Sure, but it probably doesn’t account for &lt;a href=&quot;https://react-spectrum.adobe.com/blog/building-a-button-part-1.html&quot;&gt;the 3-part blog post published by Adobe Spectrum about handling touch devices due to various browser inconsistencies&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But who cares right? The deadline is tomorrow, and you just need a button that LooksGood™. You have no time to understand all that goes into it. You just see that it isn’t exactly the button that you need so you make your own. How hard could it be? It works on my machine and everyone uses a Mac 16” Pro Ultimate HD Max (I have no idea what the names of these things are). Button #13 is born.&lt;/p&gt;
&lt;p&gt;That’s why I’m now making a clear distinction between a component library and a design system. The collection of various shiny objects and the thoughtful curation of related usable resources.&lt;/p&gt;
&lt;p&gt;Importantly, just because thought was involved doesn’t immediately make it a design system. You could &lt;em&gt;think&lt;/em&gt; that a certain use-case is an exception, but oftentimes that’s where the thinking stops. The design system is meant to have the resources to take all of the information and synthesize it down to the perfect component. Realistically, we don’t have resources to do this. Either we don’t get the time, cooperation, or complete requirements. It’s garbage in and garbage out. No wonder people are losing faith in design systems.&lt;/p&gt;
&lt;p&gt;But I haven’t. That’s why I’ve dedicated my free time to them because I’m confident there are perfect versions of them. Versions that could work for everyone. And continuing to copy existing systems strapped for resources themselves isn’t where we’ll find improvements. We need to pivot for &lt;a href=&quot;https://bradfrost.com/blog/post/a-global-design-system/&quot;&gt;universal solutions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is because I’m a user too. And every time I visit a site with wild inconsistencies and poor usability I know I have the experience to make an impact and you can too. 💪&lt;/p&gt;</content:encoded></item><item><title>DS Events, Backstage</title><link>https://blog.damato.design/posts/ds-events-backstage</link><guid isPermaLink="true">https://blog.damato.design/posts/ds-events-backstage</guid><pubDate>Tue, 19 Sep 2023 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;Last month I had the pleasure and honor of being invited to speak in &lt;a href=&quot;https://www.youtube.com/watch?v=DPvxOcWlLn0&quot;&gt;a webinar hosted by Knapsack about theming in complex ecosystems&lt;/a&gt;. On that day, there were 3 different design system related events happening; two of them scheduled at the same time. It was at this point I thought that it would be helpful to have all the events in our community to be in one place. So I did what any of us do: I bought a domain.&lt;/p&gt;
&lt;h2 id=&quot;helping-hands&quot;&gt;Helping hands&lt;/h2&gt;
&lt;p&gt;After &lt;a href=&quot;https://twitter.com/donniedamato/status/1696534327004364890&quot;&gt;I announced the idea in a tweet&lt;/a&gt; that day, &lt;a href=&quot;https://twitter.com/joshdesignnz&quot;&gt;Josh Harwood&lt;/a&gt; mentioned he had a similar idea (and also similar domain) so we ended up collaborating on the project. First jamming with ideas on LinkedIn but later using the &lt;a href=&quot;https://design-systems.slack.com/&quot;&gt;Design Systems Slack&lt;/a&gt; which is much better suited for this kind of work. My wife &lt;a href=&quot;https://twitter.com/jipdamato&quot;&gt;Jen&lt;/a&gt; was also involved in the process, making this a &lt;a href=&quot;https://ds.house/&quot;&gt;Design Systems House&lt;/a&gt; project.&lt;/p&gt;
&lt;h2 id=&quot;concept&quot;&gt;Concept&lt;/h2&gt;
&lt;p&gt;The idea was simple, we want some feed of events that you can view all events that have design systems content. What the registration link is, if it’s online or in-person (or both) and most importantly when the event will be in relation to other events. Josh gathered a lot of different concepts to compare and identified the treatments that we liked the most. We trimmed down some of the ideas for the sake of an MVP; something that gets the general idea across.&lt;/p&gt;
&lt;h2 id=&quot;design&quot;&gt;Design&lt;/h2&gt;
&lt;p&gt;A blank canvas is always a hard place to start. Luckily I had something for a long time ago (my second codepen) which was going to kick this off.&lt;/p&gt;
&lt;iframe height=&quot;300&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;Material Design Hover Animated Calendar Icon&quot; src=&quot;https://codepen.io/fauxserious/embed/yNrgNJ?default-tab=html%2Cresult&quot; frameborder=&quot;no&quot; loading=&quot;lazy&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/fauxserious/pen/yNrgNJ&quot;&gt;
Material Design Hover Animated Calendar Icon&lt;/a&gt; by Donnie D’Amato (&lt;a href=&quot;https://codepen.io/fauxserious&quot;&gt;@fauxserious&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 created this pen in 2015 after seeing the design of the Google Calendar icon and gave it some small animation on hover. I was super proud of it back then so I’m glad it finally found a home in a project after all these years. I thought it would be functional by flipping to the date as your scroll.&lt;/p&gt;
&lt;p&gt;The event card design was mostly composed of the essential data we wanted to show; the who, what, where, when, and how. I recommended that the location tags were a separate treatment from other qualifiers to make them easier to identify. I felt if we had a collection of tags that were related, scanning them would be more difficult. Granted, we did also add filters so maybe this is less of a concern now.&lt;/p&gt;
&lt;h2 id=&quot;development&quot;&gt;Development&lt;/h2&gt;
&lt;p&gt;The important thing to know about me is that I don’t often build applications. I’m commonly petrified of trying to connect to a database so if I was going to pull this off, I knew I needed something simple. I’ve been loving &lt;a href=&quot;https://astro.build/&quot;&gt;Astro&lt;/a&gt; recently for it’s ability to do absolute magic and since what we were making was essentially a blog where each post is an event, it seemed like a good choice. Eventually, we decided that it didn’t make sense for each event to have its own page, since we weren’t showing much more information between the feed and the page. Plus, the purpose for folks visiting isn’t to stay on this site, but to go register at another.&lt;/p&gt;
&lt;h3 id=&quot;dates&quot;&gt;Dates&lt;/h3&gt;
&lt;p&gt;Inevitably, this kind of a site will require a heavy use of datetime manipulation. Unlike many developers, the &lt;code&gt;Date()&lt;/code&gt; object doesn’t scare me; I’ve been working with it for years and understand what it’s doing most often. Here’s some of the finer points of the system in this regard.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Writing a UTC date into the client is trivial when the timezone is included. It’ll be localized when finally rendered as a string.&lt;/li&gt;
&lt;li&gt;Speaking of rendering as a localized string, you always want to reach for &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat&quot;&gt;&lt;code&gt;Intl.DateTimeFormat&lt;/code&gt;&lt;/a&gt; and its related methods. It even has the ability to give you &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/formatToParts&quot;&gt;the parts of a localized date&lt;/a&gt;. We use this for the mini calendar pages.&lt;/li&gt;
&lt;li&gt;The harder part is having the client enter a datetime and sending it as UTC. The form that creates an event uses a &lt;code&gt;&amp;lt;input type=&amp;quot;datetime-local&amp;quot;/&amp;gt;&lt;/code&gt; which should give some indication of what it does. However, this was the easiest way to put a datetime input on the page.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;timezones&quot;&gt;Timezones&lt;/h3&gt;
&lt;p&gt;A helpful fact about working with Josh is that he lives in New Zealand, on the complete opposite side of the world from me in New York. For him, it is all too common for him to need to translate dates and times into his local time just to see if they are remotely available to participate. The process of converting to local time is annoying and we wanted to change that. This is where the global timezone input was born and it was a bit of a challenge.&lt;/p&gt;
&lt;p&gt;The list of timezones is very simple, as is getting the user’s current timezone. One line of code each:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; timezones&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; Intl&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.supportedValuesOf&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;timeZone&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; userTZ&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; Intl&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.DateTimeFormat&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.resolvedOptions&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;().timeZone;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The hard part is getting the UTC offset from the timezone name. For that, I had to do &lt;a href=&quot;https://stackoverflow.com/a/64262840&quot;&gt;some digging&lt;/a&gt; but here’s the final result:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; getUtcOffset&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(timeZone) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; timeZoneName&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; Intl&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.DateTimeFormat&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;ia&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        timeZoneName&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;shortOffset&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        timeZone&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        .formatToParts&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        .find&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;((i) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; i&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.type &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;timeZoneName&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;).value;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; matchData&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; timeZoneName&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.match&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;/([+-])(\d&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;)(?::(\d&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;matchData) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; sign&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; hour&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; minute&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; matchData;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [sign&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (hour &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;0&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.padStart&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;0&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (minute &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;0&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.padStart&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;0&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;)]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.join&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Using the timezone name, format it’s parts using &lt;code&gt;&amp;#39;ia&amp;#39;&lt;/code&gt; (&lt;a href=&quot;https://en.wikipedia.org/wiki/Interlingua&quot;&gt;Interlingua&lt;/a&gt;) to return the &lt;code&gt;timeZoneName&lt;/code&gt; value.&lt;/li&gt;
&lt;li&gt;That value should include the UTC offset with some parts that we parse out with a Regular Expression.&lt;/li&gt;
&lt;li&gt;We deconstruct the Regular Expression result and reconcatenate with padded digits.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Using that function, with the value from a &lt;code&gt;&amp;lt;input type=&amp;quot;datetime-local&amp;quot;&amp;gt;&lt;/code&gt;, I can create a UTC time in the client with a bit more concatenation.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; onChange&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({ target }) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; isoUtcDate&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; Date&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;target&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.value&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;:00&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;getUtcOffset&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(timeZone)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.toISOString&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There might be a cleaner way to do this if I was to dive into source of &lt;a href=&quot;https://date-fns.org/&quot;&gt;&lt;code&gt;date-fns&lt;/code&gt;&lt;/a&gt; or &lt;a href=&quot;https://momentjs.com/&quot;&gt;&lt;code&gt;moment&lt;/code&gt;&lt;/a&gt;. Something to look into for later.&lt;/p&gt;
&lt;p&gt;Now the global timezone input will change all of the dates and times to the user’s selected timezone. This is very helpful when inputting a new event; so you don’t need to lookup what it is for your timezone. You can enter the information in the timezone announced by the event.&lt;/p&gt;
&lt;p&gt;One of the fast-follows we’ll need to do is including the timezone for physical events. Since seeing the local datetime when the event is posted in another timezone is confusing. This should be just saving the user’s timezone when the data is input for physical events, assuming they aren’t trying to convert themselves. For the moment, the time at each event links to the global timezone input so a person can update it themselves but it would probably be helpful to display this on the physical events upfront. It’s also not immediately clear which timezone a physical event might be in for all visitors.&lt;/p&gt;
&lt;h3 id=&quot;images&quot;&gt;Images&lt;/h3&gt;
&lt;p&gt;What is a post without an image? We knew we wanted to give each event some more personality than just the event details. So including an image was important. My idea was to have a few options; image upload or image “search”. The image upload is easy using &lt;code&gt;&amp;lt;input type=&amp;quot;file&amp;quot;/&amp;gt;&lt;/code&gt; with a little bit of CSS magic to make it look consistent with other inputs. However, the image search was much more involved.&lt;/p&gt;
&lt;p&gt;The idea was for the user to input a URL and we’d intelligently get an image based on the URL. Here’s the steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If the URL is an image, use it.&lt;/li&gt;
&lt;li&gt;If the URL is an HTML page, check for an Open Graph image and use that.&lt;/li&gt;
&lt;li&gt;If the URL is an HTML page and doesn’t have an Open Graph image, take a screenshot.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;From my experience, whenever I hear screenshot, I immediately think I need a headless chrome browser to render the HTML. I initially started using &lt;a href=&quot;https://playwright.dev/&quot;&gt;Playwright&lt;/a&gt; and got everything working in development on my local machine. However, as soon as I uploaded the build to Netlify, it failed. Why? Playwright is too large. I tried looking at tutorials for folks successfully using it or &lt;a href=&quot;https://pptr.dev/&quot;&gt;Puppeteer&lt;/a&gt; in a Netlify function but nothing I tried worked.&lt;/p&gt;
&lt;p&gt;I was pretty defeated after several hours of work trying to figure out how to make this smaller. At the end of it all, I came to my wife with a big hug and all she said was “is there anything else you could do?” That’s when it hit me; maybe I don’t need headless chrome at all?&lt;/p&gt;
&lt;p&gt;For two of the 3 options, all I’m really doing is a &lt;code&gt;fetch()&lt;/code&gt; request and I don’t need any dependencies for that. That left the last option, the screenshot. I searched for a few hours, trying different packages and looking at their sizes. I finally found one that worked; &lt;a href=&quot;https://www.npmjs.com/package/red-snapper&quot;&gt;&lt;code&gt;red-snapper&lt;/code&gt;&lt;/a&gt;. I don’t know how, but this package is only 160kB (gzip) and makes screenshots pretty easily. The one gotcha is that you’ll want to add the &lt;code&gt;delay&lt;/code&gt; option so the page has a chance to load.&lt;/p&gt;
&lt;p&gt;One small addition for this was including an &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/AbortController&quot;&gt;&lt;code&gt;AbortController&lt;/code&gt;&lt;/a&gt; to the fetch as it’s possible a URL might not be valid so instead of the normal timeout, we abort ourselves.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; fetchWithTimeout&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(resource&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; options &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {}) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;timeout&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 8000&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; options;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; controller&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; AbortController&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; setTimeout&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; controller&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.abort&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; timeout);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; response&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; fetch&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(resource&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;      ...&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;options&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      signal&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; controller&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.signal  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;    clearTimeout&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(id);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; response;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;verifying&quot;&gt;Verifying&lt;/h3&gt;
&lt;p&gt;So if a person makes a new event, how do we review it? I knew I wanted to avoid creating some &lt;a href=&quot;https://en.wikipedia.org/wiki/Role-based_access_control&quot;&gt;RBAC&lt;/a&gt; system all for the sake of 3 of us looking at some data once in a while. I had the idea of using Github PRs for reviewing the submissions. However, when I started looking at the &lt;a href=&quot;https://octokit.github.io/rest.js/&quot;&gt;official docs&lt;/a&gt;, I was immediately overwhelmed. There’s just so much you need to know to get things working. That’s when I caved; I asked &lt;a href=&quot;https://chat.openai.com/&quot;&gt;ChatGPT&lt;/a&gt; to just tell me how to do it.&lt;/p&gt;
&lt;p&gt;As much as I believe that technology will eventually help up do things more efficiently, I will rarely use it personally. There’s something about having the ability to do it myself that makes me feel useful. The Github docs on the other hand make me feel completely inadequate. I think the other reason why I think this was appropriate is because this isn’t really my area of expertise. My world is the front of the frontend so that’s where I want to comfortably keep my expertise.&lt;/p&gt;
&lt;p&gt;Back on track and a few &lt;code&gt;await&lt;/code&gt; calls later, I can create a PR for the repository with a new event submission. Now we can just login using Github, make approvals and merge with an auto-deploy. It even has branch previews courtesy of Netlify!&lt;/p&gt;
&lt;p&gt;Eventually, we’ll make the form more intelligent. The error messaging isn’t great and we’d like to have a predetermined list of locations to choose before creating a new one. However, as long as there is a good attempt at completing it, it’ll submit. Plus, someone from the team can always correct an entry before it’s posted.&lt;/p&gt;
&lt;h3 id=&quot;reviewing-the-past&quot;&gt;Reviewing the past&lt;/h3&gt;
&lt;p&gt;One of the things we discussed about was what happens when events are complete? Do we not show them, or maybe show them differently? Do we have the ability to link to resources produced by the event? I had strong feelings about the last point. It was important to me that we review an event once. Otherwise it would be exhausting trying to collect all the information from past events on a regular basis. Additionally, if we were going to put the responsibility on the person who submitted the event in the first place; I’d need some way of reidentifying who they were to update the post. That returns back to the RBAC problem; now with user creation. I squashed the idea just because of my abilities but I do see the benefit in a more complete system.&lt;/p&gt;
&lt;p&gt;As for the other features of past events. We opted to do a pagination approach, where the first event at the top of the feed in the homepage is the next upcoming event and following events go forwards in time. If you go back one page, the first event at the top will be the most recent &lt;em&gt;past&lt;/em&gt; event and subsequent events go further back in time. Historical events are stylized in a sepia filter (including the pagination button when you will travel to a historical page) to make them look more old-timey.&lt;/p&gt;
&lt;h3 id=&quot;pagination&quot;&gt;Pagination&lt;/h3&gt;
&lt;p&gt;Speaking of pagination, this was trickier than I expected since we aren’t starting at the first or last event, but something in the middle. When you load the page, we determine what today’s date is and then mark the next event according to that date. Then we separate pages offset by that date. I had a few tries trying to get this to work and had plenty of fumbles. Not because of the date comparisons, since the &lt;code&gt;Date()&lt;/code&gt; object value is a number, but juggling what to show on which page.&lt;/p&gt;
&lt;p&gt;Eventually, I figured to just segregate the events as if they were paged each time you filter and/or paginate but I wasn’t quite sure what that algorithm looked like. Here’s what my thought process was.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Get today’s date, find the next event in the list and get it’s &lt;code&gt;index&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Chunk the events (into pages) so that the &lt;code&gt;index&lt;/code&gt; is the &lt;em&gt;first&lt;/em&gt; in its chunk.&lt;/li&gt;
&lt;li&gt;Find the chunk that has the &lt;code&gt;index&lt;/code&gt; and return that chunk.&lt;/li&gt;
&lt;li&gt;If paginating, return the chunk offset by the target chunk and given page.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I was feeling a bit confused here too, so I tried giving some prompts to ChatGPT here too. However, it was not given me the right results and I knew why. It would find the next event and just &lt;em&gt;move&lt;/em&gt; it to the first of some chunk. What I wanted was for the the first chunk to be adjusted so that the target event would wind up as the first. After seeing the general approach, I realized I just needed the handy &lt;code&gt;%&lt;/code&gt; operator. Here’s the final function:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;chunk&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(arr &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; []&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; size&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; target) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; chunks&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; currentChunk &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; chunkSize &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; arr&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.indexOf&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(target) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; size &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; size;&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:var(--astro-code-token-keyword)&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;arr&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; chunkSize) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [arr];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; item&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; of&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; arr) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        currentChunk&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.push&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(item);&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:var(--astro-code-token-keyword)&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;currentChunk&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; ===&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; chunkSize) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;            chunks&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.push&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(currentChunk);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;            currentChunk &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;            chunkSize &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; size;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;chunks&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.includes&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(currentChunk)) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        chunks&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.push&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(currentChunk);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; chunks;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So if I had an array with the numbers 1 through 15, and wanted the size to be &lt;code&gt;5&lt;/code&gt; but the target as &lt;code&gt;8&lt;/code&gt;, the resulting array would look like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;[[&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 6&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 7&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;8&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 9&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 11&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 12&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;13&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 14&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 15&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice how the &lt;code&gt;8&lt;/code&gt; is at the first position in its chunk.&lt;/p&gt;
&lt;h3 id=&quot;web-components-in-astro&quot;&gt;Web Components in Astro&lt;/h3&gt;
&lt;p&gt;I love web components and I’ve been using them for years. Astro supports web components but it’s not well documented. I had a lot of learnings trying to use them in this project and here’s some takeaways that will be helpful.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You don’t need to use the ShadowDOM, Astro will encapsulate styles within the framework.&lt;/li&gt;
&lt;li&gt;You can create a one-page &lt;code&gt;.astro&lt;/code&gt; component as a web component, and import into other places across the project.&lt;/li&gt;
&lt;li&gt;Spread &lt;code&gt;Astro.props&lt;/code&gt; on the component and &lt;code&gt;&amp;lt;slot/&amp;gt;&lt;/code&gt; is your friend.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;my-component&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; ...Astro.props&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;slot&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;&amp;lt;!-- default content can go here --&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;slot&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;my-component&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;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:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;/* Encapsulated styles are here, no ShadowDOM required */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;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:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    class&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; MyComponent&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; extends&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; HTMLElement&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;        constructor&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;            super&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;            /* Do whatever you need here */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-constant)&quot;&gt;    customElements&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.define&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;my-component&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; MyComponent);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then in another &lt;code&gt;.astro&lt;/code&gt; file  (assuming you have a &lt;code&gt;@components&lt;/code&gt; alias):&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;import MyComponent from &amp;#39;@components/MyComponent.astro&amp;#39;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;MyComponent&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;my-component&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;Stuff for the slot&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;MyComponent&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I did a mix of this kind of web component and ShadowDOM ones. You can identify the older components from the newer ones because of this.&lt;/p&gt;
&lt;h3 id=&quot;global-events&quot;&gt;Global events&lt;/h3&gt;
&lt;p&gt;I also needed the components to talk to each other. Normally I’d select them from the DOM to begin listening but. I got lazy and just sent most of the events over the &lt;code&gt;document&lt;/code&gt;, so many of the components have a &lt;code&gt;customEvent&lt;/code&gt; method that sends a &lt;code&gt;detail&lt;/code&gt; key in the event with the data it has processed for another component to pick up and use for something. One of the longest chains in the system goes like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;On timezone change, get the full event list.&lt;/li&gt;
&lt;li&gt;On full event list request, filter the events.&lt;/li&gt;
&lt;li&gt;On filter complete, paginate the results.&lt;/li&gt;
&lt;li&gt;On pagination complete, render the results.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It’s possible that other events will trigger the flow. For example, you can trigger the filters without requiring a timezone request, which also sends a message to reset pagination (since filtering will re-adjust the results on pages).&lt;/p&gt;
&lt;h3 id=&quot;filtering&quot;&gt;Filtering&lt;/h3&gt;
&lt;p&gt;And speaking of filtering, this was a bit tricky as well. The direction I chose was that if a filter was checked, it should be shown. So if nothing is checked, then nothing is shown. Then we check all the filters by default so the visitor sees everything by default and they can remove as needed. The data behind it looks like it might work the same, but it doesn’t. Specifically the “Free and Premium” filter which reads from a single data point &lt;code&gt;free&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If both are checked I need to show both &lt;code&gt;free: true&lt;/code&gt; and &lt;code&gt;free: false&lt;/code&gt; events.&lt;/li&gt;
&lt;li&gt;If one is unchecked, I need to hide what the checkbox represents.&lt;/li&gt;
&lt;li&gt;If both are unchecked, I need to hide both.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Meanwhile, the “In-person and Remote” filter works much easier:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If In-person is unchecked, hide in-person events.&lt;/li&gt;
&lt;li&gt;If Remote is unchecked, hide online events.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We considered having filters for location but that would require an API key to some geolocation service which would have cost some more money. We hope to collect some locations in the coming months to use for filtering as a next step.&lt;/p&gt;
&lt;h3 id=&quot;release-ready&quot;&gt;Release ready&lt;/h3&gt;
&lt;p&gt;A site needs all the finishing touches. Jen made the site’s Open Graph and Twitter images. She also chose the colors for the site since I’m color deficient. Josh recommended an &lt;code&gt;.ics&lt;/code&gt; file to be created for subscriptions, so people can just add our calendar to see the events as they are added. Josh also put together the list of events that were upcoming as they were announced so we could add to the site when we were ready. There’s a lot more ideas that were at play but not enough time to implement. &lt;a href=&quot;https://forms.gle/jLxTi7ENnqrY2a7C9&quot;&gt;We’ll collect more feedback&lt;/a&gt; and have time to revisit later this year.&lt;/p&gt;
&lt;p&gt;We’re excited to finally show off this past month’s worth of afterhours work to bring our community closer together. &lt;a href=&quot;https://ds.events&quot;&gt;Visit the site&lt;/a&gt; and subscribe to a feed. If you know of a design systems event coming, help our community by adding it.&lt;/p&gt;</content:encoded></item><item><title>Dynamic Astro Collections</title><link>https://blog.damato.design/posts/dynamic-collections</link><guid isPermaLink="true">https://blog.damato.design/posts/dynamic-collections</guid><pubDate>Mon, 10 Apr 2023 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;When I first heard of &lt;a href=&quot;https://astro.build/&quot;&gt;Astro&lt;/a&gt; it sounded incredible. I thought of it as the next step after working with &lt;a href=&quot;https://www.11ty.dev/&quot;&gt;11ty&lt;/a&gt;. That step is requiring framework support such as &lt;a href=&quot;https://docs.astro.build/en/guides/integrations-guide/#official-integrations&quot;&gt;React, Vue, or others&lt;/a&gt;. While I often avoid frameworks, a framework allows for a shared understanding with a team to achieve a result within the guardrails, &lt;a href=&quot;https://twitter.com/CherryJimbo/status/1643778121944952833&quot;&gt;even if convoluted&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So for documentation sites that expect to host components written in a framework, Astro seems like a solid choice. However, my initial review of the project had some serious critism when finally attempting to build a site.&lt;/p&gt;
&lt;h2 id=&quot;low-maintenance&quot;&gt;Low maintenance&lt;/h2&gt;
&lt;p&gt;One of the most important qualities of a documentation site is for it to be low maintenance. This can result in lots of different kinds of optimizations but one of the first I think about is how easy it is to create a new page and have it immediately appear in a navigational interface. It’s a non-starter if I need to configure simple navigation by letting the project know that I made a new page and where that new page is in the project. We can do better, but at the time Astro just couldn’t do this without accessing some internal methods and even then it didn’t seem possible without rebuilding the entire site. The ergonomics weren’t great and I decided to pause on the project.&lt;/p&gt;
&lt;h2 id=&quot;content-collections&quot;&gt;Content collections&lt;/h2&gt;
&lt;p&gt;Astro has come a long way since my complaints. Earlier this year with the release of their v2.0, they have introduced &lt;a href=&quot;https://astro.build/blog/introducing-content-collections/&quot;&gt;Content Collections&lt;/a&gt;. Much of their post is talking about it being typesafe which is good but what I was more excited about was the ability to fetch content and manipulate it to render navigation.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.astro.build/en/guides/content-collections/&quot;&gt;The documentation suggests a few ways to configure a collection&lt;/a&gt; but all of them assume you are manually curating the collection. I’d like to avoid this so you don’t need to provide much instruction past “put files here”.&lt;/p&gt;
&lt;p&gt;Assume the following project &lt;code&gt;/src&lt;/code&gt; file structure, reduced for brevity. We’ll be discussing each top-level directory and its setup to get this to work.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;├──&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt; components&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;│&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt;   └──&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt; MainNavigation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;│&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt;       └──&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt; index.jsx&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;├──&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt; content&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;│&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt;   ├──&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt; components&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;│&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt;   │&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt;   ├──&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt; button.mdx&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;│&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt;   │&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt;   └──&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt; ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;│&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt;   ├──&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt; foundations&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;│&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt;   │&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt;   ├──&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt; color.mdx&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;│&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt;   │&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt;   └──&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt; ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;│&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt;   ├──&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt; ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;│&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt;   └──&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt; config.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;├──&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt; layouts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;│&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt;   └──&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt; Page.astro&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;├──&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt; pages&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;│&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt;   ├──&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [collection]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;│&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt;   │&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt;   └──&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [...slug].astro&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;│&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt;   └──&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt; index.astro&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;├──&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt; utils&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;│&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt;   └──&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt; getAllCollections.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;└──&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string)&quot;&gt; ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;content&quot;&gt;Content&lt;/h3&gt;
&lt;p&gt;The following is an example of how to &lt;a href=&quot;https://docs.astro.build/en/guides/content-collections/#defining-a-collection-schema&quot;&gt;define a collection from the Astro docs&lt;/a&gt;. The most important part here is the &lt;code&gt;config.js&lt;/code&gt; file shown below.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;// 1. Import utilities from `astro:content`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { z&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; defineCollection } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;astro:content&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;// 2. Define your collection(s)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; blogCollection&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; defineCollection&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  schema&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; z&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.object&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    title&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; z&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.string&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  })&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;// 3. Export a single `collections` object to register your collection(s)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;//    This key should match your collection directory name in &amp;quot;src/content&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; collections&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  &amp;#39;blog&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; blogCollection&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note the last comment. The key needs to match your collection directory name. This means that when you add a new directory, this file needs to know and have definitions added. I want to avoid that, so here’s my version:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; path &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;path&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { z&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; defineCollection } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;astro:content&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; glob&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;meta&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.glob&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;./**&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;/* vite */&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:var(--astro-code-token-keyword)&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; collectionNames&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; Object&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.keys&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(glob)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.map&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;((filepath) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; path&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.basename&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;path&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.dirname&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(filepath)));&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:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; schema&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  schema&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; z&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.object&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    title&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; z&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.string&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; assignCollection&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(acc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; name) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; Object&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.assign&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(acc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { [name]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; defineCollection&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;schema }) });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; collections&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; collectionNames&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.reduce&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(assignCollection&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first new part is using &lt;a href=&quot;https://vitejs.dev/guide/features.html#glob-import&quot;&gt;the &lt;code&gt;glob&lt;/code&gt; function from Vite&lt;/a&gt; to get all files relative to this config file. We could be more specific here to look only for &lt;code&gt;.md{x,} &lt;/code&gt; but this works fine as-is.&lt;/p&gt;
&lt;p&gt;After using the &lt;code&gt;glob&lt;/code&gt; function to get the files, we parse the filepaths to get the directory that each one is in. This assumes that each section (eg., &lt;code&gt;/blog&lt;/code&gt;) is only one level deep. This will return an array of directory names that we’ll use later. For us, this return &lt;code&gt;[&amp;#39;components&amp;#39;, &amp;#39;foundations&amp;#39;]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Finally, the &lt;code&gt;collectionNames&lt;/code&gt; array is reduced using the &lt;code&gt;assignCollection&lt;/code&gt; function. This creates a new collection definition with each section in the same way we would have done it manually in the original example. During the build step, Astro will create types based on the schema.&lt;/p&gt;
&lt;p&gt;Before moving on, make sure you have some content in the markdown files (including the &lt;code&gt;title&lt;/code&gt; frontmatter) to test out.&lt;/p&gt;
&lt;h3 id=&quot;pages&quot;&gt;Pages&lt;/h3&gt;
&lt;p&gt;Next we’ll dynamically render our pages. We’ve set up a &lt;a href=&quot;https://docs.astro.build/en/core-concepts/routing/#dynamic-routes&quot;&gt;dynamic route&lt;/a&gt; at &lt;code&gt;[collection][...slug].astro&lt;/code&gt;. As you might have guessed, the &lt;code&gt;collection&lt;/code&gt; part is the directory name found within &lt;code&gt;/content&lt;/code&gt; from earlier. For our file structure, this’ll eventually write &lt;code&gt;components&lt;/code&gt; and &lt;code&gt;foundations&lt;/code&gt; into the url. The slug is created from the file names in each of these directories (&lt;code&gt;button&lt;/code&gt; and &lt;code&gt;color&lt;/code&gt;). Here’s how we get that to work using frontmatter in the &lt;code&gt;[...slug].astro&lt;/code&gt; file which is mostly copied from &lt;a href=&quot;https://docs.astro.build/en/guides/content-collections/#building-for-static-output-default&quot;&gt;the official documentation&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; Page &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;@layouts/Page.astro&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; getAllCollections &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;@utils/getAllCollections.js&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; getStaticPaths&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; content&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; getAllCollections&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; content&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.map&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;((entry) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    params&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { slug&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; entry&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.slug&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; collection&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; entry&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.collection }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    props&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { entry }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;entry&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; Astro&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.props;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Content&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; entry&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.render&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A few things to note. The &lt;code&gt;@layouts&lt;/code&gt; alias points to the &lt;code&gt;/layouts&lt;/code&gt; directory where I have a single &lt;code&gt;Page.astro&lt;/code&gt; as the base layout. The &lt;code&gt;@utils&lt;/code&gt; alias points to reusable functions. &lt;a href=&quot;https://docs.astro.build/en/guides/aliases/&quot;&gt;These aliases can be setup&lt;/a&gt; in the &lt;code&gt;tsconfig.json&lt;/code&gt; file at the root of the project. The &lt;code&gt;getAllCollections&lt;/code&gt; function we will need to use twice. Once here to make the paths to content, and a second time to build navigation. I imagine there’s a way for this to run once, but this was easiest for me while I explored this solution.&lt;/p&gt;
&lt;p&gt;This is what the &lt;code&gt;getAllCollections&lt;/code&gt; function looks like:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { getCollection } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;astro:content&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { collectionNames } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;@content/config&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; default&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; getAllCollections&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; collections&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; Promise&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.all&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    collectionNames&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.map&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;((name) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; getCollection&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(name));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; collections&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.flat&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;getCollection&lt;/code&gt; function from Astro will get the data for a single given collection. We have created a list of collections back at the &lt;code&gt;content/config.js&lt;/code&gt; file as an export called &lt;code&gt;collectionNames&lt;/code&gt;. So we loop over that to get all of the content and write the section it came from within the metadata. After resolving all the promises, we flatten the result because this is a single-level navigational structure. If you need nesting, you might not want to flatten the results here and have your own tree returned.&lt;/p&gt;
&lt;p&gt;At this point we should be rendering pages dynamically. However, we’d also like to automatically generate a navigational interface from this too.&lt;/p&gt;
&lt;h3 id=&quot;layouts&quot;&gt;Layouts&lt;/h3&gt;
&lt;p&gt;In the &lt;code&gt;Page.astro&lt;/code&gt; file, we’ll need to manipulate the result of the &lt;code&gt;getAllCollections&lt;/code&gt; function to create a tree for navigation.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; path &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;path&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; getAllCollections &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;@utils/getAllCollections.js&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; buildNavigation&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(collections) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; collections&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.reduce&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;((acc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; entry) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;    // collection is the collectionName string&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;collection&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; entry;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;acc[collection]) acc[collection] &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;slug&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; data&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; collection;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    acc[collection][&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.title] &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; path&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.join&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;meta&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;BASE_URL&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; collection&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; slug);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; collections&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; getAllCollections&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; tree&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; buildNavigation&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(collections);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As we loop over the items in the collection, we get the &lt;code&gt;title&lt;/code&gt; and build the &lt;code&gt;url&lt;/code&gt;.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;If you want your navigation to have a specific order, you’d need to either include additional metadata in the &lt;code&gt;/content&lt;/code&gt; markdown files for this function to sort by and/or provide an order to the &lt;code&gt;collectionNames&lt;/code&gt; within the &lt;code&gt;content/config.js&lt;/code&gt;.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;h3 id=&quot;components&quot;&gt;Components&lt;/h3&gt;
&lt;p&gt;Finally we create a navigation component to consume the &lt;code&gt;tree&lt;/code&gt;. This could be done in any framework, even as an Astro component since it can be a list of links. I’ve chosen to use React to have several subcomponents in the same file.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; React &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;react&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; Section&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({ section&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; entries }) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; navigation&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; Object&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.entries&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(entries);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;navigation&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;{section}&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;navigation&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.map&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(([title&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; url]) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;          &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Item&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{ title } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{ url } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{ name }/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        )}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; Item&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({ title&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; url }) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; href&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{ url }&amp;gt;{ title }&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; default&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; MainNavigation&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({ tree }) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; navigation&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; Object&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.entries&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(tree);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;navigation&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;nav&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;navigation&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.map&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(([section&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; entries]) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;          &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Section&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; section&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{ section } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;entries&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{ entries } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{ section }/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        )}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;nav&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There’s nothing special to see here. The incoming &lt;code&gt;tree&lt;/code&gt; prop is the object that represents the navigation for the content made in the &lt;code&gt;buildNavigation&lt;/code&gt; function from earlier. The component will traverse the tree and render out the links.&lt;/p&gt;
&lt;p&gt;Finally, back in the &lt;code&gt;Page.astro&lt;/code&gt; file, import the &lt;code&gt;&amp;lt;MainNavigation/&amp;gt;&lt;/code&gt; and render it in the body passing in the &lt;code&gt;tree&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;MainNavigation&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; tree&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{ tree }&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that’s it! Now as markdown pages are created in the &lt;code&gt;/content&lt;/code&gt; directory, they are automatically added to the navigation.&lt;/p&gt;</content:encoded></item><item><title>Dynamic Storybook</title><link>https://blog.damato.design/posts/dynamic-storybook</link><guid isPermaLink="true">https://blog.damato.design/posts/dynamic-storybook</guid><pubDate>Tue, 14 Jun 2022 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;When I was exploring the next version of the design system for &lt;a href=&quot;https://www.compass.com/&quot;&gt;Compass&lt;/a&gt;, I was really interested in how I could keep designers from recreating symbols that we already have represented in code. They’d have to painstakingly make all of the possible states and interactions for every component for the design library. I knew there was a better way so I cobbled a few systems together in order to do it.&lt;/p&gt;
&lt;h2 id=&quot;legacy-system&quot;&gt;Legacy system&lt;/h2&gt;
&lt;p&gt;I was an early adopter of &lt;a href=&quot;https://storybook.js.org/&quot;&gt;Storybook&lt;/a&gt; and leveraged it to visualize the components I was building for the new design system. Writing a story was helpful to create one ideal state, or perhaps wiring it into the knobs addon allows for different configurations to happen with a few button clicks. However, what I really wanted was to generate stories based on the configuration options for each component. I was working on a very early prototype with web components so I didn’t have proptypes to hook into. I opted to create an &lt;code&gt;component.props.js&lt;/code&gt; file for each component to help generate configurations.&lt;/p&gt;
&lt;p&gt;From here, I used a package called &lt;a href=&quot;https://www.npmjs.com/package/combos&quot;&gt;&lt;code&gt;combos&lt;/code&gt;&lt;/a&gt; to create all the possible permutations of options and then create a new Storybook file to read with those new generated components. This was also used to create the files required for &lt;a href=&quot;https://www.npmjs.com/package/@brainly/html-sketchapp&quot;&gt;&lt;code&gt;html-sketchapp&lt;/code&gt;&lt;/a&gt;, which could render the HTML into &lt;a href=&quot;https://www.sketch.com/&quot;&gt;Sketch&lt;/a&gt; symbols.&lt;/p&gt;
&lt;h2 id=&quot;component-story-format&quot;&gt;Component Story Format&lt;/h2&gt;
&lt;p&gt;Storybook is no longer focusing on their initial implementation of writing stories, &lt;a href=&quot;https://github.com/storybookjs/storybook/blob/next/lib/core/docs/storiesOf.md&quot;&gt;the &lt;code&gt;storiesOf()&lt;/code&gt; function&lt;/a&gt;, in favor of the &lt;a href=&quot;https://github.com/ComponentDriven/csf&quot;&gt;Component Story Format (CSF)&lt;/a&gt;. The CSF is described as an open standard for UI component examples based on JavaScript ES6 modules. And the way to write a story seems fairly simple:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-keyword)&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; default&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { title&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;atoms/Button&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; text&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;Hello&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; emoji&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;😀😎👍💯&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The default export is the metadata about your story; the title, the component, and maybe some additional configuration options. Each named export is a story. So in the above example, you’d have two stories. One named “Text” and one named “Emoji”. And coming soon, &lt;a href=&quot;https://storybook.js.org/blog/component-story-format-3-0/&quot;&gt;CSF v3&lt;/a&gt; will introduce an even smaller amount of code to create a story:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-keyword)&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; default&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { component&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; Button };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; text&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { args&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { children&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;Hello&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; } };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; emoji&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { args&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { children&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;😀😎👍💯&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; } };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, if you know anything about the JavaScript module ecosystem you’ll see the problem with my goal. &lt;strong&gt;There’s no way to generate stories using CSF&lt;/strong&gt;. In fact, Storybook doesn’t even treat this file as a &lt;em&gt;real&lt;/em&gt; module at first. Storybook will actually read this file, create an &lt;a href=&quot;https://en.wikipedia.org/wiki/Abstract_syntax_tree&quot;&gt;abstract syntax tree (AST)&lt;/a&gt; and then begin parsing the file for information &lt;a href=&quot;https://github.com/storybookjs/storybook/blob/next/lib/csf-tools/src/CsfFile.ts&quot;&gt;[source]&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Let’s compare this to the original &lt;code&gt;storiesOf()&lt;/code&gt; method of writing stories.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;storiesOf&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;atoms/Button&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; module&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;  .add&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;text&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;Hello&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;  .add&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;emoji&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;😀😎👍💯&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can see that the original method of writing stories is more flexible and allows for someone to create a collection of stories and begin iterating to add to Storybook. Here’s a cute one-liner to define a collection of stories.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; stories&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;  text&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;Hello&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;  emoji&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;😀😎👍💯&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Object&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.entries&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(stories)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.reduce&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;((acc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; ([name&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; fn])) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; acc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.add&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(name&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; fn)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; storiesOf&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;Button&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; module&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Interestingly, it seems that &lt;a href=&quot;https://medium.com/@domyen/storiesof-is-not-deprecated-598c322588c&quot;&gt;CSF compiled to &lt;code&gt;storiesOf()&lt;/code&gt;&lt;/a&gt; for Storybook but I’m not sure if that’s still the case.&lt;/p&gt;
&lt;h2 id=&quot;if-it-aint-broke&quot;&gt;If it ain’t broke&lt;/h2&gt;
&lt;p&gt;While Storybook no longer recommends the &lt;code&gt;storiesOf()&lt;/code&gt; approach because it &lt;a href=&quot;https://storybook.js.org/blog/storybook-on-demand-architecture/&quot;&gt;conflicts with improvement plans&lt;/a&gt;; we can still use it today. Here’s how I’d begin to integrate with a React ecosystem; reading &lt;a href=&quot;https://www.npmjs.com/package/prop-types&quot;&gt;&lt;code&gt;PropTypes&lt;/code&gt;&lt;/a&gt; to generate stories.&lt;/p&gt;
&lt;p&gt;First, we need a way to read proptypes from a component. Luckily, there’s a package for that: &lt;a href=&quot;https://www.npmjs.com/package/parse-prop-types&quot;&gt;&lt;code&gt;parse-prop-types&lt;/code&gt;&lt;/a&gt;. Here’s how we might begin to use this:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; parsePropTypes &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;parse-prop-types&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; default&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (component) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; proptypes&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; parsePropTypes&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(component);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;If you get a collection of types that all return as &lt;code&gt;&amp;#39;custom&amp;#39;&lt;/code&gt;, you’ll need to include the following before defining proptypes for each component.&lt;/p&gt;&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;parse-prop-types&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For more information, like the return object structure, I recommend reading &lt;a href=&quot;https://github.com/diegohaz/parse-prop-types/blob/master/README.md&quot;&gt;the project’s &lt;code&gt;README.md&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;Next, we’ll need to prepare a collection of properties and possible values. For &lt;code&gt;type: &amp;#39;bool&amp;#39;&lt;/code&gt; and &lt;code&gt;type: &amp;#39;oneOf&amp;#39;&lt;/code&gt;, the values are fairly straight forward. We’ll put these in a lookup object for easy access.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; DEFAULT_TYPE_ASSIGN&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  &amp;#39;bool&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  &amp;#39;oneOf&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; ({ meta }) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; meta&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.value&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For the inputs like &lt;code&gt;number&lt;/code&gt; or &lt;code&gt;string&lt;/code&gt;, we’ll need to allow custom fixtures to be included. We’ll prepare an &lt;code&gt;options&lt;/code&gt; argument for our function to supply this.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; default&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (component&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; options) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;fixtures&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; options;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; proptypes&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; parsePropTypes&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(component);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;fixtures&lt;/code&gt; option will be an object that has each prop as a key and an array of possible values. Now we can send that into our assignments; choosing the correct fixture prior to running the function. We’ll see how this works later.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; DEFAULT_TYPE_ASSIGN&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  &amp;#39;bool&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  &amp;#39;oneOf&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; ({ meta }) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; meta&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.value&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  &amp;#39;string&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; ({ fixture }) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; fixture&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  &amp;#39;number&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; ({ fixture }) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; fixture&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can continue to add more as needed. I specifically omit the &lt;code&gt;func&lt;/code&gt; type since it’s not a visual change but you can include it if it’ll help your project.&lt;/p&gt;
&lt;p&gt;Ok, we’re ready to loop through all of the proptypes.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; DEFAULT_TYPE_ASSIGN&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  &amp;#39;bool&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (acc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { property } ) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; Object&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.assign&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(acc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { [property]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;] })&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  &amp;#39;string&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (acc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { property&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; fixture }) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; Object&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.assign&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(acc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { [property]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; fixture })&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  &amp;#39;number&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (acc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { property&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; fixture }) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; Object&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.assign&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(acc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { [property]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; fixture })&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  &amp;#39;oneOf&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (acc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { property&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; meta } ) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; Object&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.assign&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(acc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { [property]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; meta&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.value })&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; isFn&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (fn) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; typeof&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; fn &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;function&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; values&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; Object&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.entries&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(propTypes)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.reduce&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;((acc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [property&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; meta]) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; fn&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; DEFAULT_TYPE_ASSIGN&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;meta&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.name];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; isFn&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(fn) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; fn&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(acc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { meta&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; property&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; fixture&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; fixtures[property] }) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; acc;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice, I’ve updated the functions in the lookup to have an accumulator as the first parameter; each will return the accumulator with the values for each property if it exists. Otherwise, it will return the unaltered accumulator.&lt;/p&gt;
&lt;p&gt;Ok, now we’re ready to create permutations. I’m using a more recent package for this: &lt;a href=&quot;https://www.npmjs.com/package/combinate&quot;&gt;&lt;code&gt;combinate&lt;/code&gt;&lt;/a&gt;. Let’s start putting everything together.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; parsePropTypes &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;parse-prop-types&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; combinate &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;combinate&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; DEFAULT_TYPE_ASSIGN&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  &amp;#39;bool&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (acc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { property } ) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; Object&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.assign&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(acc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { [property]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;] })&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  &amp;#39;string&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (acc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { property&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; fixture }) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; Object&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.assign&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(acc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { [property]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; fixture })&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  &amp;#39;number&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (acc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { property&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; fixture }) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; Object&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.assign&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(acc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { [property]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; fixture })&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  &amp;#39;oneOf&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (acc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { property&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; meta } ) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; Object&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.assign&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(acc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { [property]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; meta&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.value })&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; isFn&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (fn) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; typeof&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; fn &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;function&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; default&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (component&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; options) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;fixtures&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; options &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; propTypes&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; parsePropTypes&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(component);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; values&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; Object&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.entries&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(propTypes)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.reduce&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;((acc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [property&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; meta]) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; fn&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; DEFAULT_TYPE_ASSIGN&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;meta&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.name];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; isFn&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(fn) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; fn&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(acc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { meta&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; property&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; fixture&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; fixtures[property] }) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; acc;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; storyArgs&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; combinate&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(values);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The new &lt;code&gt;storyArgs&lt;/code&gt; variable holds an array of objects, but we’re not quite done yet. We need to have one large collection with the structure of &lt;code&gt;{ name: { ...args } }&lt;/code&gt;, where the &lt;code&gt;name&lt;/code&gt; is a unique identifier for each story. I opted for a simple &lt;a href=&quot;https://www.npmjs.com/package/@sindresorhus/slugify&quot;&gt;&lt;code&gt;slugify&lt;/code&gt;&lt;/a&gt; of the &lt;code&gt;JSON&lt;/code&gt; to create the identifier.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; slugify &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;@sindresorhus/slugify&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; storyArgs&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; combinate&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(values)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.reduce&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;((acc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; combo) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; JSON&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.stringify&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(combo);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; Object&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.assign&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(acc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;slugify&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(str)]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; combo });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point you can just return the resulting &lt;code&gt;storyArgs&lt;/code&gt; and pipe them into the &lt;code&gt;storiesOf()&lt;/code&gt; method approach that I suggested above:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; React &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;react&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; as&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; Button } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;./Button&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { storiesOf } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;@storybook/react&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; everythingAllAtOnce &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;../src&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;// Your custom generator function&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:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; fixtures&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { text&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;hello&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;😀😎👍💯&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;] };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; stories&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; everythingAllAtOnce&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(Button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { fixtures })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Object&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.entries&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(stories)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.reduce&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;((acc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; ([name&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; args])) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; acc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.add&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(name&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;args }/&amp;gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; storiesOf&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;Button&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; module&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or, if you’re really fancy, you could provide more options to just have the function run the &lt;code&gt;storiesOf()&lt;/code&gt; method internally.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;everythingAllAtOnce&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(Button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  fixtures&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  storiesOf&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt; // Used internally to begin defining the stories produced&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;  callback&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (args) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;args }/&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt; // How each story should render with the given args&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Not showing the code to implement here, you can use your imagination.&lt;/p&gt;
&lt;h2 id=&quot;cool-what-should-we-do-with-this&quot;&gt;Cool, what should we do with this?&lt;/h2&gt;
&lt;p&gt;For starters, this would a good way to begin generating assets for your component library. The &lt;a href=&quot;https://story.to.design/&quot;&gt;story.to.design&lt;/a&gt; tool by &lt;a href=&quot;https://divriots.com/&quot;&gt;‹div›RIOTS&lt;/a&gt; can transform stories into &lt;a href=&quot;https://www.figma.com/&quot;&gt;Figma&lt;/a&gt; components. This’ll help keep the Figma library up to date with the code because it’s pulling from the code. Imagine, writing minimal code to generate all of these assets!&lt;/p&gt;
&lt;p&gt;It’s also a good way to determine configurations that you may not have expected. Perhaps you notice with review of the permutations, icons in inline buttons don’t work well, so you might want to set a conditional in the component to either warn or omit the icons.&lt;/p&gt;
&lt;p&gt;Speaking of checking configurations, this would be great for testing. You could ensure a check in every configuration for some baseline metrics and even assert that all configurations that use the same props will render in the same expected way. This is truly a full coverage scenario without writing much code.&lt;/p&gt;
&lt;h2 id=&quot;full-circle&quot;&gt;Full circle&lt;/h2&gt;
&lt;p&gt;This brings me back to the introduction of the CSF format; which doesn’t support this type of behavior at all. There’s &lt;a href=&quot;https://www.notion.so/Storybook-Combos-a5abecd87e9c4e0b86277244af093aea&quot;&gt;a document&lt;/a&gt; outlining the possibility of “Storybook Combos”, which is only a proposal with no affirmitive direction yet.&lt;/p&gt;
&lt;p&gt;I hope that whatever the future holds for Storybook that the team sees the benefits of &lt;code&gt;storiesOf()&lt;/code&gt; and attempts to support the ability for dynamic stories in the future. I’m sure the design system community has more use-cases for dynamic stories that are past just the needs outlined above.&lt;/p&gt;</content:encoded></item><item><title>Feeding trolls</title><link>https://blog.damato.design/posts/feeding-trolls</link><guid isPermaLink="true">https://blog.damato.design/posts/feeding-trolls</guid><pubDate>Tue, 28 Jun 2022 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;I published &lt;a href=&quot;https://gridless.design&quot;&gt;gridless.design&lt;/a&gt; a year ago this month and the initial response was overwhelming. Many people across the design industry shared and discussed these ideas for the coming weeks and I really enjoyed seeing all of the positive affirmations and interest in how we might avoid grids in artboards to hand off responsive web designs.&lt;/p&gt;
&lt;p&gt;However, there were others that didn’t understand the point I was trying to make. This is my opportunity to address these comments and help clarify where the mark was missed.&lt;/p&gt;
&lt;h2 id=&quot;reddit&quot;&gt;Reddit&lt;/h2&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://www.reddit.com/r/Frontend/comments/oq1ogb/comment/h690qdi/?utm_source=share&amp;utm_medium=web2x&amp;context=3&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;It reads like a long-form rant complete with broken grammar.&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://www.reddit.com/r/Frontend/comments/oq1ogb/comment/h690qdi/?utm_source=share&amp;utm_medium=web2x&amp;context=3&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;del_rio&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;p&gt;Rant is probably true. The fact that we’ve been attempting to design the web like a canvas instead of a document is a complaint about the norms that we’ve accepted. It’s important to state the problem before providing a solution.&lt;/p&gt;
&lt;p&gt;As for the broken grammar, I think that’s a bit unfair. I’m a native English speaker but my grammar shouldn’t be criticized for the idea I’m trying to convey.&lt;/p&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://www.reddit.com/r/Frontend/comments/oq1ogb/comment/h690qdi/?utm_source=share&amp;utm_medium=web2x&amp;context=3&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;Not a single argument was supported with a citation even though they’re presented as “it is recommended”&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://www.reddit.com/r/Frontend/comments/oq1ogb/comment/h690qdi/?utm_source=share&amp;utm_medium=web2x&amp;context=3&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;del_rio&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;p&gt;While must of the historical part of the thesis goes uncited and could be improved, it’s not as important as the gridless approach which is net-new. How do you cite new ideas? The gridless approach is novel and never before documented. The closest concept is responsive design but it is not the same since the target for the change is artboard exploration specifically; not the web. The recommendations are based on the observations which are documented here in this thesis.&lt;/p&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://www.reddit.com/r/Frontend/comments/oq1ogb/comment/h6d1r1s/?utm_source=share&amp;utm_medium=web2x&amp;context=3&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;It also has a ridiculously long introduction that explains the basics and superficial history of web design/development which seems utterly pointless considering the target audience.&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://www.reddit.com/r/Frontend/comments/oq1ogb/comment/h6d1r1s/?utm_source=share&amp;utm_medium=web2x&amp;context=3&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;teokk&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;p&gt;The point of the history is to provide a primer to all the concepts that caused the grid to be included in the web design process and what the web aimed to support.&lt;/p&gt;
&lt;h2 id=&quot;hacker-news&quot;&gt;Hacker News&lt;/h2&gt;
&lt;p&gt;These were responses to a &lt;a href=&quot;https://css-irl.info/is-it-time-to-ditch-the-design-grid/&quot;&gt;blog post&lt;/a&gt; by &lt;a href=&quot;https://michellebarker.co.uk/&quot;&gt;Michelle Barker&lt;/a&gt; about my writing entitled “Is it time to ditch the design grid?“.&lt;/p&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://news.ycombinator.com/item?id=28120029&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;No, of course, not, grid is a fundamental structure in graphic design.&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://news.ycombinator.com/item?id=28120029&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;qkqk&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;p&gt;That’s the thing, we aren’t talking about “graphic” design, we’re talking about “web” design. Graphic design principles &lt;em&gt;can&lt;/em&gt; translate to the web but sometimes not directly. This is one of those cases. The traditional artboard is not an accurate representation of the web. Identifying this is the first step to considering new approaches to support what the web expects.&lt;/p&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://news.ycombinator.com/item?id=28120029&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;no, no, no. Remember “top: 50%; transform: translateY(-50%);” to vertically center things before Flexbox and Grid? We’re not going back to those days!&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://news.ycombinator.com/item?id=28120029&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;qkqk&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;p&gt;The commenter is reacting to the &lt;a href=&quot;https://www.freecodecamp.org/news/the-fab-four-technique-to-create-responsive-emails-without-media-queries-baf11fdfa848/&quot;&gt;Fab Four&lt;/a&gt; approach. The negative dimension that I am quoted on writing is the foundational part of the calculation that allows for a container-query-like layout conditional in that approach. The approach is very complicated looking at first glance and admittedly it isn’t helpful with all the additional variables that I included in order for the &lt;code&gt;gap&lt;/code&gt; property to be supported but the end result of allowing the contents to determine when they should change the layout instead of the page is clearly helpful as precedented by native container queries coming to browsers very soon.&lt;/p&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://news.ycombinator.com/item?id=28120029&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;Renaming the column-gap property to —gap-spacing doesn’t mean you’re “not using a grid.”&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://news.ycombinator.com/item?id=28120029&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;qkqk&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;p&gt;This person might have missed the intro of gridless.design but I call out that I am not talking about &lt;code&gt;display: grid;&lt;/code&gt; as an tool to avoid. You can use things that are named “grid” in the process but I’m specifically interested in how we can avoid including the design grid in the hand off process to engineers and even further not using it at all when designing for the web. It has very little to do with the CSS property of the same name.&lt;/p&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://news.ycombinator.com/item?id=28119631&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;As somebody who just began using grids in their designs, I can say that grids can have a really nice effect on a lot of layouts.&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://news.ycombinator.com/item?id=28119631&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;Rd6n6&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;p&gt;It’s true! Grids make layouts easy and its very much the reason why they work so well for graphic design. However, the final publishing of a graphic design will always have the same layout of elements, the same copy, the same orientation, etc.. On the web, this simply is not the case. What your originally provided in your design will very often not be the same as what your end-user sees. I call out the affects of translation alone and how words will often break out of neatly designed containers. Forcing your content into pink cages will ultimately break usability in designs in the most extreme cases.&lt;/p&gt;
&lt;p&gt;I think learning about the design grid for people introduced to design is helpful as a elementary concept but for more scalable experiences, the grid will do more harm than good.&lt;/p&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://news.ycombinator.com/item?id=28119293&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;Visually, the “no” grid website just looked like a website created with CSS Grid. I was expecting some sort of design that would be different. Are we missing something?&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://news.ycombinator.com/item?id=28119293&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;djstein&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;p&gt;Yes, you’re missing the content of the site! The site itself was not designed using a design grid but instead designed within the rules of the web. You might be able to provide some 12 column overlay that could roughly should some alignment on the web pages but it would be a coincidence.&lt;/p&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://news.ycombinator.com/item?id=28119381&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;I think the idea is not that the design is without a grid, but more on how it handles being resized&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://news.ycombinator.com/item?id=28119381&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;oo0shiny&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;p&gt;No, the design of the site is truly completed without a design grid. However, while the design of the site was done without a design grid, the content is more important here.&lt;/p&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://news.ycombinator.com/item?id=28119556&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;The principles of a grid-based design are still adhered to though. This isn’t “gridless” in any real sense&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://news.ycombinator.com/item?id=28119556&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;michaelscott&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;p&gt;The principles you might be referring to are &lt;a href=&quot;https://www.smashingmagazine.com/2014/03/design-principles-visual-perception-and-the-principles-of-gestalt/&quot;&gt;Gestalt principles&lt;/a&gt; which I call out as foundational to the gridless concepts. The design grid helps designers adhere to those principles but those principles do not &lt;em&gt;come from&lt;/em&gt; the grid.&lt;/p&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://news.ycombinator.com/item?id=28121459&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;I was surprised by how many right angles, rectangles, and perpendicular lines I saw for a site focused on not using a grid.&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://news.ycombinator.com/item?id=28121459&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;itronitron&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;p&gt;Cute. Alignment found in a web page does not need to be the result of a design grid. It will be a result of applying Gestalt principles with the rules of authoring web documents.&lt;/p&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://news.ycombinator.com/item?id=28120128&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;This seems like more of a commentary on responsive design than on grid based layouts. There’s a big difference between designing for print/for the web, and a really good designer will be able to give you a grid layout that performs well between breakpoints.&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://news.ycombinator.com/item?id=28120128&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;spcebar&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;p&gt;I was on board with this until the last phrase. I believe a informed designer will give you guidance about what should occur when the ideal layout isn’t possible on a user’s device. Not necessarily as a designed comp, but as a conversation. Prescribing what happens at a breakpoint is a lazy solution, in my opinion. Considering how elements might shift in different viewports, orientations, translations, writing-modes, etc. is not scalable as artboards. Having conversations will make more inclusive designs.&lt;/p&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://news.ycombinator.com/item?id=28121827&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;I, personally, prescribe to the 1px grid system - where I write all my widths, heights and offsets in multiples of 1px. It helps keep things consistent.&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://news.ycombinator.com/item?id=28121827&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;munk-a&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;p&gt;Thanks, I hate it.&lt;/p&gt;</content:encoded></item><item><title>Fetching web component definitions</title><link>https://blog.damato.design/posts/fetching-definitions</link><guid isPermaLink="true">https://blog.damato.design/posts/fetching-definitions</guid><pubDate>Tue, 12 Apr 2022 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;I love web components. Being able to just plop a custom element onto a page with all the functionality baked in without needing a framework or bundling to make it work is just liberating. I know there’s a lot of overhead that comes with it that libraries and frameworks aim to abstract but I just enjoy having the low-level ability to do whatever you want.&lt;/p&gt;
&lt;p&gt;The trickiest part of web components for me has been how to identify when a web components, which is written as HTML, needs to be defined through JavaScript. From a performance point-of-view, we don’t want to send JavaScript to the page for components that aren’t there. On the flip side, we don’t want to miss components that apppear later in the lifecycle of the page.&lt;/p&gt;
&lt;p&gt;The technique I’m about to explain is something I was working on at &lt;a href=&quot;https://compass.com&quot;&gt;Compass&lt;/a&gt; but was never completed. Since then I’ve also enhanced the approach to be a bit easier to setup.&lt;/p&gt;
&lt;h2 id=&quot;registrar&quot;&gt;Registrar&lt;/h2&gt;
&lt;p&gt;The core of the approach uses an immediately invoked function expression (IIFE) which does a few things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Listens for new custom elements appearing on the page.&lt;/li&gt;
&lt;li&gt;Fetches definitions for elements that are not defined.&lt;/li&gt;
&lt;li&gt;Listens within new shadow roots for additional elements.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s describe how it does each of these.&lt;/p&gt;
&lt;h3 id=&quot;listening-for-new-custom-elements&quot;&gt;Listening for new custom elements&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://davidwalsh.name/detect-node-insertion&quot;&gt;technique for detecting when an element appears in the DOM&lt;/a&gt; is not new. It was first discovered by &lt;a href=&quot;http://www.backalleycoder.com/&quot;&gt;Daniel Buchner&lt;/a&gt; as early as 2012. This was the basis behind identifying when a custom element appears on the page with a few changes.&lt;/p&gt;
&lt;p&gt;First, I use &lt;code&gt;visibility&lt;/code&gt; as the trigger for the animation. The reason for this is because it is not commonly used for animations like &lt;code&gt;opacity&lt;/code&gt; would be. This avoids possible conflicts where these elements would be animated more traditionally. So the declaration block that triggers the animation would begin to look like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;... {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  animation&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; undefined-detection .1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;ms&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;@keyframes&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; undefined-detection {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  to { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;visibility&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; visible&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The missing piece is the selector to target these custom elements. In my original implementation, I would generate the list of elements to find here however, there is a better way. Because what we are looking for is custom elements that are undefined, there’s a CSS selector that can target all of these.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;:not&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(:defined) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  animation&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; undefined-detection .1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;ms&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;@keyframes&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; undefined-detection {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  to { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;visibility&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; visible&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yep, that’s it. Now the &lt;code&gt;undefined-detection&lt;/code&gt; animation will trigger for all custom elements that are not yet defined.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;h3 id=&quot;greedy-registration&quot;&gt;Greedy registration&lt;/h3&gt;&lt;p&gt;I’ve noticed that custom elements that are on the page from extensions or other libraries will also attempt to be requested and ultimately fail since they aren’t part of the library. This would be a benefit for having an explicit list of elements to listen for but the failures can be caught and ignored in this implementation or you could filter by prefix (i.e.; &lt;code&gt;ds-button&lt;/code&gt; but not &lt;code&gt;random-button&lt;/code&gt;).&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;So we will write this CSS to the &lt;code&gt;&amp;lt;head/&amp;gt;&lt;/code&gt; of the page within the registrar and begin listening for the animation.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; ANIMATION_NAME&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;undefined-detection&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; CSS&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; `&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  :not(:defined) { animation: &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;ANIMATION_NAME&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; } &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  @keyframes &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;ANIMATION_NAME&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; { to { visibility: visible } }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; registrar&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; observe&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(root) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;root) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    root&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.addEventListener&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;animationstart&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; onAnimationStart);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; styles&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; Object&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.assign&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;document&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.createElement&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;style&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      type&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;text/css&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      textContent&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; CSS&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    document&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;head&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.insertBefore&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(styles&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; document&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;head&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.lastChild);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;  function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; onAnimationStart&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({ animationName&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; target }) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (animationName &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;!==&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; ANIMATION_NAME&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;    // tagName is the custom element name&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; tagName&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; target&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;tagName&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.toLowerCase&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;    // target is the element identified&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-function)&quot;&gt;  observe&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;document&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.documentElement);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;})()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;fetching-the-definition&quot;&gt;Fetching the definition&lt;/h2&gt;
&lt;p&gt;This requires a bit of infrastructure. In my custom element library, each component is bundled into its own IIFE, available at &lt;code&gt;components/[COMPONENT_NAME].iife.js&lt;/code&gt; in relation to the registrar. We can then determine the location of the components when the registrar is invoked with the following script.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; SOURCE_DIR&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; URL&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;document&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;currentScript&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.src).&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;href&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.replace&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;/[&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;^&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;/]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;*$&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code above determines the url where the current script is located and then removes the &lt;code&gt;registrar.iife.js&lt;/code&gt; file name. I haven’t found a cleaner way to do this without the ugly regex and without requiring to know the file name here. I wish browsers had the &lt;a href=&quot;https://nodejs.org/api/path.html&quot;&gt;&lt;code&gt;path&lt;/code&gt; module from Node&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Then we can determine the location of the components by building a url with this variable.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; src&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; URL&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;`components/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;tagName&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;.iife.js`&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; SOURCE_DIR&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From there, it’s easy to load the definition at this location. Here’s what the registrar looks like with this included.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; ANIMATION_NAME&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;undefined-detection&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; CSS&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; `&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  :not(:defined) { animation: &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;ANIMATION_NAME&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; } &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  @keyframes &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;ANIMATION_NAME&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; { to { visibility: visible } }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; SOURCE_DIR&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; URL&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;document&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;currentScript&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.src).&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;href&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.replace&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;/[&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;^&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;/]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;*$&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; registrar&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; elements&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; Set&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;  function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; observe&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(root) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;root) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    root&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.addEventListener&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;animationstart&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; onAnimationStart);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; styles&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; Object&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.assign&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;document&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.createElement&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;style&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      type&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;text/css&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      textContent&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; CSS&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    document&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;head&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.insertBefore&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(styles&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; document&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;head&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.lastChild);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;  function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; onAnimationStart&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({ animationName&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; target }) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (animationName &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;!==&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; ANIMATION_NAME&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; tagName&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; target&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;tagName&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.toLowerCase&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;    register&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(tagName);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;  function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; register&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(tagName) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;elements&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.has&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(tagName)) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    elements&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.add&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(tagName);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; script&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; Object&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.assign&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;document&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.createElement&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;script&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      type&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;text/javascript&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      defer&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;      onload&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; script&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.remove&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;      onerror&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; script&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.remove&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      src&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; URL&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;`components/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;tagName&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;.iife.js`&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; SOURCE_DIR&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    document&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;head&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.appendChild&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(script);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-function)&quot;&gt;  observe&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;document&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.documentElement);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;})()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The additional parts added are to ensure we don’t fetch definitions for things we are currently loading or have already loaded and to clean up the scripts being added to the page after they have completed.&lt;/p&gt;
&lt;h2 id=&quot;handling-shadow-roots&quot;&gt;Handling shadow roots&lt;/h2&gt;
&lt;p&gt;So we’ve solved for when custom elements appear on the page but not when they appear within other custom elements. There’s a little more work to do here.&lt;/p&gt;
&lt;p&gt;When a custom element is identified, we’ll want to listen inside of its shadow root for undefined elements. We can do that in the event trigger.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; onAnimationStart&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({ animationName&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; target }) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (animationName &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;!==&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; ANIMATION_NAME&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; tagName&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; target&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;tagName&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.toLowerCase&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;  register&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(tagName);&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:var(--astro-code-token-comment)&quot;&gt;  // When the custom element is defined, begin looking for custom elements within&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  window&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;customElements&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.whenDefined&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(tagName)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.then&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; observe&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;target&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.shadowRoot));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will also require us to change the &lt;code&gt;observe&lt;/code&gt; function since shadow roots do not have a &lt;code&gt;&amp;lt;head/&amp;gt;&lt;/code&gt;. This is what the final registrar function looks like.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; ANIMATION_NAME&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;undefined-detection&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; CSS&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; `&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  :not(:defined) { animation: &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;ANIMATION_NAME&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; } &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  @keyframes &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;ANIMATION_NAME&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; { to { visibility: visible } }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; SOURCE_DIR&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; URL&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;document&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;currentScript&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.src).&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;href&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.replace&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;/[&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;^&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;/]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;*$&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; registrar&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; elements&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; Set&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-comment)&quot;&gt;  // Determine the anchor and target to set the resources&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; location&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(root) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; root &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; document&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.documentElement&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;      ?&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { anchor&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; document&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.head&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; target&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; document&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;head&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.lastChild }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;      :&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { anchor&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; target&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.firstChild };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;  function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; observe&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(root) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;root) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    root&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.addEventListener&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;animationstart&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; onAnimationStart);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; styles&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; Object&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.assign&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;document&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.createElement&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;style&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      type&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;text/css&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      textContent&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; CSS&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-comment)&quot;&gt;    // Here&amp;#39;s where we determine where to attach the resources&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;anchor&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; target&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; location&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(root);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    anchor&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.insertBefore&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(styles&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; target);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;  function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; onAnimationStart&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({ animationName&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; target }) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (animationName &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;!==&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; ANIMATION_NAME&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; tagName&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; target&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;tagName&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.toLowerCase&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;    register&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(tagName);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    window&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;customElements&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.whenDefined&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(tagName)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.then&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; observe&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;target&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.shadowRoot));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;  function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; register&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(tagName) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;elements&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.has&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(tagName)) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    elements&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.add&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(tagName);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; script&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; Object&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.assign&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;document&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.createElement&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;script&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      type&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;text/javascript&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      defer&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;      onload&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; script&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.remove&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;      onerror&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; script&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.remove&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      src&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; URL&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;`components/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;tagName&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;.iife.js`&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; SOURCE_DIR&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    document&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;head&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.appendChild&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(script);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-function)&quot;&gt;  observe&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;document&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.documentElement);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;})()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;missing-pieces&quot;&gt;Missing pieces&lt;/h2&gt;
&lt;p&gt;One edge case that this approach might not catch is when custom elements are dynamically added to defined elements.&lt;/p&gt;
&lt;p&gt;In other words, if &lt;code&gt;&amp;lt;my-element&amp;gt;&lt;/code&gt; appears on the page, we define it and immediately add the listener to &lt;em&gt;only&lt;/em&gt; that shadow root. While it does determine if any custom elements within its lifecycle need definitions, later &lt;code&gt;&amp;lt;my-element&amp;gt;&lt;/code&gt; components added to the page will already be defined and therefore not trigger dynamically added custom elements within those later components (because the triggering resources aren’t added to subsquent shadow roots).&lt;/p&gt;
&lt;p&gt;To have true coverage, the triggering resources would need to be added to &lt;em&gt;all&lt;/em&gt; shadow roots. Luckily, this could be solved by importing the node detection CSS separately within each component which will trigger the registrar to fetch the definition; something that could be part of the library building script.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; CSS &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;../registrar.js&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; MyElement&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; extends&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; window&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;HTMLElement&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  constructor&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;    super&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    this&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.attachShadow&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({ mode&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;open&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; }).innerHTML &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; `&amp;lt;style type=&amp;quot;text/css&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;CSS&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;lt;/style&amp;gt;`&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;window&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;customElements&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.define&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;my-element&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; MyElement);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;h3 id=&quot;listening-for-defined&quot;&gt;Listening for defined&lt;/h3&gt;&lt;p&gt;You may have considered another approach to use node detection to just look for defined elements.&lt;/p&gt;&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;:defined {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  animation&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; defined-detection .1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;ms&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;From there we could just add the target resources to each element; skipping the &lt;code&gt;customElements.whenDefined&lt;/code&gt; check since the CSS animation trigger should catch it instead.&lt;/p&gt;&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.addEventListener&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;animationend&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; ({ animationName&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; target }) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;   if&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (animationName &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;!==&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;defined-detection&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;   observe&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;target&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.shadowRoot);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There’s one catch, the &lt;code&gt;:defined&lt;/code&gt; selector will trigger for &lt;em&gt;all elements&lt;/em&gt; (&lt;code&gt;&amp;lt;html/&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;div/&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;p/&amp;gt;&lt;/code&gt;, etc.) and for every single one of them found on the page. While you could certainly filter for specific custom elements with open shadow roots, it’s still a lot of callbacks firing. Another reason why having a list of elements to update or pre-updating with the triggering resources seems to be better approaches.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;h2 id=&quot;all-together-now&quot;&gt;All together now&lt;/h2&gt;
&lt;p&gt;Once you have the files bundled and deployed, you can just add the registrar to each page and it’ll begin fetching definitions. I’ll add &lt;code&gt;defer&lt;/code&gt; so it doesn’t block the page from loading.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; src&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;registrar.iife.js&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; defer&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that’s it, we’re automagically getting the definitions for web components on-demand!&lt;/p&gt;</content:encoded></item><item><title>Fit Text Responsibly</title><link>https://blog.damato.design/posts/fit-text-responsibly</link><guid isPermaLink="true">https://blog.damato.design/posts/fit-text-responsibly</guid><pubDate>Fri, 05 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;Adam Argyle made &lt;a href=&quot;https://bsky.app/profile/nerdy.dev/post/3m77ve6qvcc2q&quot;&gt;a post on Bluesky today&lt;/a&gt; announcing a new property called &lt;code&gt;text-grow&lt;/code&gt; is now available in Chrome Canary 145+. Much of the folks I follow there have been very excited about it. But I’m here to tell you to be careful.&lt;/p&gt;
&lt;h2 id=&quot;about-fit-text&quot;&gt;About fit text&lt;/h2&gt;
&lt;p&gt;The concept of fit text is not new. The idea is that the size of the text will adapt to each line such that every line fills the width of the container. It’s sort of like text justification, but instead of adjusting the spacing between words and letters, it adjusts the size of the text itself. Here’s the video from Adam’s post:&lt;/p&gt;
&lt;video src=&quot;https://nerdy.dev/media/text-grow.mp4&quot; controls&gt;&lt;/video&gt;
&lt;p&gt;Lea Verou &lt;a href=&quot;https://bsky.app/profile/lea.verou.me/post/3m5hyr7ldj22j&quot;&gt;asked around the internet&lt;/a&gt; to get use-cases for the behavior and while there’s no shortage of reasons why someone might want it, this calls for the Jurassic Park meme.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/your-scientists.jpg&quot; alt=&quot;Your scientists were so preoccupied with whether or not they could that they didn’t stop to think if they should&quot;/&gt;&lt;/p&gt;
&lt;h2 id=&quot;accessibility-awareness&quot;&gt;Accessibility awareness&lt;/h2&gt;
&lt;p&gt;Any time that we mess with the size of text, it makes me think of how my parents have made changes in their devices to set the text size for it to be more legible. I think about how the text we enter into our experiences is not necessarily the text that another user will see after translating it. It drives the point home that the less we try to control how text appears, the better the experiences are for the widest audience.&lt;/p&gt;
&lt;p&gt;In &lt;a href=&quot;https://nerdy.dev/css-text-grow&quot;&gt;Adam’s post on his website&lt;/a&gt;, he’s linked to several resources. One of them is the discussion about adding this feature to CSS. I want to call out some of the quotes from the discussion specifically regarding accessibility:&lt;/p&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://github.com/w3c/csswg-drafts/issues/2528#issuecomment-2770953200&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;I just finished a research project on personalization and accessibility (under review) and the most common action taken by people who are considered low vision is to customize text size. Inability to change text size is a pretty significant barrier for many people. &lt;a href=&quot;https://www.sciencedirect.com/science/article/pii/S2214109X20304253&quot;&gt;Meta-analysis research from 2020&lt;/a&gt; estimates that around 600 million people worldwide would be considered on the spectrum of “low vision” to blind, which was roughly 8% of the world population in 2020. These numbers are expected to grow, due to compounding socio-economic factors, by 2050. This isn’t just a small slice of people.&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://github.com/w3c/csswg-drafts/issues/2528#issuecomment-2770953200&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;frankelavsky&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://github.com/w3c/csswg-drafts/issues/2528#issuecomment-2772072339&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;Making text dependent on the viewport has always been problematic for accessibility, this is well documented. This is why we usually advise not to use clamp or vh/vw units in font sizes. It just overrides user preferences unnecessarily.&lt;/p&gt;&lt;p&gt;The only way this could pass muster is to require browsers to include an opt-out to the behavior. Or to ignore it when users zoom in, which would defeat the purpose of the proposal.&lt;/p&gt;&lt;p&gt;I second Patrick’s pointer at LVTF and general W3C horizontal review. It might be good to generally outline when you get specific accessibility input to ensure that proposals are feasible to implement so that all users can use them.&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://github.com/w3c/csswg-drafts/issues/2528#issuecomment-2772072339&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;yatil&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/explainers-by-googlers/css-fit-text/blob/main/README.md&quot;&gt;explainer&lt;/a&gt; mentions that there’s still an open question about accessibility for this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If an end-user tries to enlarge font size, UAs should not fit enlarged lines to the container width. Is minimum-font setting enough?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;My worry is similar to the one I have with folks reordering elements visually with CSS. Just because we have CSS technologies, doesn’t necessarily mean that they should be used in any situation. It’s not often that folks really consider the impact of every CSS decision. The large majority of developers are just picking the first solution that works and move on. Taking a moment to consider how our decisison affect more than us is a fading responsibly.&lt;/p&gt;
&lt;h2 id=&quot;maybe-not-for-screens&quot;&gt;Maybe not for screens&lt;/h2&gt;
&lt;p&gt;All that said, I think this can be used responsibly. I think for folks using CSS for print media, this could be a useful tool since after text is printed there’s no way of having user settings affect it. Many of the folks that provided visual examples in Lea’s post providing media meant for printing. In reading some of the other replies, it really looks like many of the use-cases are for non-web things. &lt;a href=&quot;https://x.com/KrisDesChacals/status/1988889941707796768/photo/1&quot;&gt;This example&lt;/a&gt; is from Kris des Chacals asking for this property for use in &lt;a href=&quot;https://obsproject.com/&quot;&gt;OBS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/G5nk67fWkAAxen5?format=png&amp;name=small&quot; alt=&quot;Displaying a question and answers like &amp;#34;Who Wants to be a Millionaire&amp;#34;&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Maybe the problem is that CSS is becoming too powerful and now we want to use it for everything. I know I do. 😅&lt;/p&gt;</content:encoded></item><item><title>Fluid Headings</title><link>https://blog.damato.design/posts/fluid-headings</link><guid isPermaLink="true">https://blog.damato.design/posts/fluid-headings</guid><pubDate>Fri, 10 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;There’s no shortage of posts that explain how to perform responsive typography. Here’s a small sample of them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.smashingmagazine.com/2023/11/addressing-accessibility-concerns-fluid-type/&quot;&gt;Addressing Accessibility Concerns With Using Fluid Type&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.smashingmagazine.com/2022/12/fluid-typography-predict-problem-users-zoom-in/&quot;&gt;Fluid Typography: Predicting A Problem With Your User’s Zoom-In&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.smashingmagazine.com/2022/01/modern-fluid-typography-css-clamp/&quot;&gt;Modern Fluid Typography Using CSS Clamp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.smashingmagazine.com/2017/05/fluid-responsive-typography-css-poly-fluid-sizing/&quot;&gt;Fluid Responsive Typography With CSS Poly Fluid Sizing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.smashingmagazine.com/2016/05/fluid-typography/&quot;&gt;Responsive And Fluid Typography With vh And vw Units&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And that’s just articles from a single website!&lt;/p&gt;
&lt;p&gt;However, in those articles no one really mentions what qualities you are meant to look out for when figuring out the values. I’ll admit the closest article to this is the first article which explains that if you use only viewport units for a &lt;code&gt;font-size&lt;/code&gt; that it’ll break the zoom expectations in the browser, which will cause a &lt;a href=&quot;https://www.w3.org/WAI/WCAG22/quickref/?versions=2.1#resize-text&quot;&gt;WCAG 1.4.4&lt;/a&gt; failure. The recommendation there is to &lt;em&gt;always&lt;/em&gt; include a non-viewport unit in the calculation with your viewport unit.&lt;/p&gt;
&lt;p&gt;Well, I’m about to turn that on its head. 🙃&lt;/p&gt;
&lt;p&gt;What I set out to do is to have a rule that helps explain what the transition should be for heading font sizes between large and small screen sizes. In other words, what the middle value of a CSS &lt;code&gt;clamp()&lt;/code&gt; function is expected to be.&lt;/p&gt;
&lt;h2 id=&quot;min-and-max&quot;&gt;Min and Max&lt;/h2&gt;
&lt;p&gt;First, we need a few numbers to start. The first two are up to you, your font family, and typescale. These will be the minimum size and the maximum size your heading is meant to be. For the purposes of example and to exaggerate the effect, let’s consider this in terms of marketing display text. Really big and fun text on desktop but somehow needs to be reasonable on a small device. In this example, I’m just going to make variables for these and they’ll be in the places where you’d expect in the &lt;code&gt;clamp()&lt;/code&gt; function:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.text-heading&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    font-size&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; clamp&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--heading-smallest)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;        /* heading change */&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--heading-largest)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    )&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The middle value is what we’re going to calculate, and we’re going to do that with a few more numbers. A minimum viewport size and a “maximum” viewport size.&lt;/p&gt;
&lt;p&gt;The minimum size that I’ll recommend is &lt;code&gt;320px&lt;/code&gt;. This comes from the &lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/reflow.html&quot;&gt;WCAG 1.4.10&lt;/a&gt; about reflow.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Vertical scrolling content at a width equivalent to 320 CSS pixels&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The “maximum” is not really the maximum viewport size. It’s closer to being a breakpoint of sorts. What this size is meant to be is the point in which the largest size that the heading is meant to be starts shrinking to the smaller size. It’ll stop shrinking at &lt;code&gt;320px&lt;/code&gt;. What we’re going to explore is what that size is meant to be.&lt;/p&gt;
&lt;p&gt;My thinking for this starts with the recommendation of number of characters for body copy, which is somewhere between 40 and 80 characters depending on your source. I typically pick a number in the middle, 60 characters, to represent the optimal reading length. Importantly, this is speaking about paragraphs. This is not meant to be the same number for headings, and in my research I couldn’t find a number that represents what the optimal character length for headings is meant to be. If there is one, please let me know.&lt;/p&gt;
&lt;p&gt;To make up for this, I figured that we typically want to lockup paragraphs with the heading. We want them to visually match together. If we’re still speaking in terms of characters and the body copy can be represented as &lt;code&gt;60rch&lt;/code&gt; (assuming that the root font size dictates body copy), then we could also set the heading maximum length in terms of those characters. So that means that the “maximum” viewport width should be &lt;code&gt;60rch&lt;/code&gt; for headings.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;You might have already set a &lt;code&gt;max-width: 60rch&lt;/code&gt; on the container for this content and be wondering why we’re calling this out specifically when it comes to headings. We’ll need this number for further calculations.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;It’s also possible that this &lt;em&gt;feels&lt;/em&gt; too large for you. If you disagree and feel that the length of the heading is meant to be shorter than the related copy, then feel free to update this value. But the expectation is that this a maximum length that causes the wrapping behavior of the heading to achieve LooksGood™ status.&lt;/p&gt;
&lt;h2 id=&quot;time-for-the-math&quot;&gt;Time for the math&lt;/h2&gt;
&lt;p&gt;Ok, these will be all of the values we need to determine the middle number. Here’s the formula:&lt;/p&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.css&quot; integrity=&quot;sha384-WsHMgfkABRyG494OmuiNmkAOk8nhO1qE+Y6wns6v+EoNoTNxrWxYpl5ZYWFOLPCM&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msub&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/msub&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msub&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/msub&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;m=(y_2-y_1)/(x_2-x_1)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;If that looks familiar, it’s because you may have read &lt;a href=&quot;/tags/typography/&quot;&gt;my other typographic posts&lt;/a&gt; that discuss a rate of change. This is trying to determine the slope of a line. Let’s write this in terms of CSS:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.text-heading&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --m&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--heading-largest) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--heading-smallest))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        / (60&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;rch&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; - 320&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Except this wont work this way in CSS. We’re not able to divide with a unit number, which would be the result of &lt;code&gt;60rch - 320px&lt;/code&gt;. While you could do some fun hacks to make this work, I’m going to suggest something different: to make everything in terms of &lt;code&gt;rem&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;--heading-largest&lt;/code&gt; and &lt;code&gt;--heading-smallest&lt;/code&gt; are probably in terms of &lt;code&gt;rem&lt;/code&gt; already or something relative to &lt;code&gt;font-size&lt;/code&gt; like &lt;code&gt;rem&lt;/code&gt;. So if we update the numbers below to also be &lt;code&gt;rem&lt;/code&gt;, then we don’t need the units in the denominator. In my experience, this seems to be the following:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.text-heading&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --m&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--heading-largest) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--heading-smallest))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        / (30 - 20&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;/* 30rem - 20rem */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now what we need to do is relate this to how the viewport changes. I specifically recommend viewport over container because having different sized headings depending on the container instead of the context of the content could be hierarchically confusing. Having all of the same heading behave identically maintains the hierarchical relationship across all areas uniformly.&lt;/p&gt;
&lt;h2 id=&quot;scaling-text&quot;&gt;Scaling text&lt;/h2&gt;
&lt;p&gt;The last part is borrowed from &lt;a href=&quot;https://css-tricks.com/linearly-scale-font-size-with-css-clamp-based-on-the-viewport/&quot;&gt;this post on CSS-Tricks&lt;/a&gt;, which also explores responsive typography but has a special distinction: when you resize the examples, the text looks like it scales as if you wired &lt;code&gt;scale()&lt;/code&gt; to the viewport for the text. I found this to be the missing part to fluid headings.&lt;/p&gt;
&lt;p&gt;My goal was to keep the wrapping composition between the “maximum” and minimum. While Pedro’s post uses JavaScript to do the heavy lifting (because the dividing problems we mentioned earlier), we can get there in CSS. In fact, our implementation is arguably &lt;em&gt;easier&lt;/em&gt; than his because we want this change to be &lt;em&gt;linear&lt;/em&gt;. In other words, as the viewport changes, the rate of change is a straight line between the max and min. What this does is &lt;em&gt;maintain the wrapping composition of the heading&lt;/em&gt; between the max and min. This is that scaling effect from the post.&lt;/p&gt;
&lt;p&gt;Here’s how we’d finish this:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.text-heading&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --m&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--heading-largest) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--heading-smallest))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        / (30 - 20&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;/* 30rem - 20rem */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    font-size&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; clamp&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--heading-smallest)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--m) * 100&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;vw&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--heading-largest)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    )&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Remember, the recommendation is for viewport units in the &lt;code&gt;font-size&lt;/code&gt; to be accompanied by some non-viewport units, which is what the &lt;code&gt;--m&lt;/code&gt; is providing. &lt;code&gt;--heading-largest&lt;/code&gt; and &lt;code&gt;--heading-smallest&lt;/code&gt; are font sizes you’ve set for headings.&lt;/p&gt;
&lt;p&gt;You can check a working example out on my &lt;a href=&quot;https://system.damato.design/?path=/docs/foundations-typography--docs&quot;&gt;design system playground&lt;/a&gt; or if you just want to watch the magic, I have a animated GIF below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/fluid-headings.gif&quot; alt=&quot;Resizing panel causing the font size to mantain wrapping behavior between &amp;#34;breakpoints&amp;#34;&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Hopefully, this takes less of the guess work into the numbers that are meant to appear in the &lt;code&gt;clamp()&lt;/code&gt; and maintains typographic lockups more regularly.&lt;/p&gt;</content:encoded></item><item><title>Font size dimensions</title><link>https://blog.damato.design/posts/font-size-dimensions</link><guid isPermaLink="true">https://blog.damato.design/posts/font-size-dimensions</guid><pubDate>Fri, 20 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;First, we used pixels to describe the size of things on the web. Most digital tools and technologies communicated in pixels so this seemed like a logical decision to use. Over time, we’ve received other units in CSS that were relative to some other amount. Percentages were based on the parent element and many other units were based on font size.&lt;/p&gt;
&lt;p&gt;The use of font size was highly misunderstood across our practice for years. One of the earliest concepts was converting &lt;code&gt;(r)em&lt;/code&gt; to pixels since many people weren’t familiar with the new units, but saw benefits to using &lt;code&gt;(r)em&lt;/code&gt; in other areas outside of updating the size of the font. Unfortunately, this eventually turned into &lt;a href=&quot;/posts/62-5&quot;&gt;the bad practice of setting &lt;code&gt;font-size: 62.5%&lt;/code&gt; on the &lt;code&gt;html&lt;/code&gt; element&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;space&quot;&gt;Space&lt;/h2&gt;
&lt;p&gt;In my later work, I did adopt the concept of using &lt;code&gt;(r)em&lt;/code&gt; to define elements outside of font size, specifically space. This looked promising since areas that had larger typography also typically have larger spacing. However, I’ve more recently walked that back. This is because of accessibility.&lt;/p&gt;
&lt;p&gt;If we decide to use font relative units to define space and a user decides to increase the font size of the text, this would also increase the amount of space between elements. This would make the overall composition very large. I realized this while exploring &lt;a href=&quot;https://complementary.space/&quot;&gt;Complementary Space&lt;/a&gt;, because I could separate what space meant at different regions. It made more sense to keep the amount of space effectively static (using pixels) between elements as long as the perceived hierarchy was maintained. As an example, as long as the space found in the hero section was larger in relation to the space found in table cells, the text could be sized up for legibility while maintaining the essence of hierarchy. This would keep the overall layout smaller while allowing the text to be as large as the user needed.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;At the time of this writing, this blog uses relative font units for space. You can see my change of perspective is very recent. If you see the source and it isn’t using relative font units, then I found time to update it.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;h2 id=&quot;width&quot;&gt;Width&lt;/h2&gt;
&lt;p&gt;Another place where people tend to try using relative units is for defining the width, either explicitly or as a limit. One of my principles for composition layout is to &lt;em&gt;not&lt;/em&gt; define widths and let the content dictate the size of its container. This isn’t always possible. One common example is when using &lt;code&gt;display: grid&lt;/code&gt;. I tend to use the &lt;code&gt;repeat(auto-fit, minmax())&lt;/code&gt; technique to define columns dynamically and this requires some dimension for the minimum or maximum. Most of the time I set this as &lt;code&gt;minmax(260px, 1fr)&lt;/code&gt; for card containing layouts and the &lt;code&gt;260px&lt;/code&gt; has very much been a LooksGood™ value that I didn’t put much thought into.&lt;/p&gt;
&lt;p&gt;So are relative font units helpful or hurtful when defining width? To get an answer we need to understand why we are setting a value for the width at all. Generally, we set a width on an element so it maintains an expected size, but why? As a thought experiment, we can consider an element primarily made up of text, we want the text to have an optimal reading composition. Lines that aren’t too long but also lines that aren’t too short. This also depends on the kind of content. Optimal line length for long form articles is around 60 characters, give or take. We can use that number to set a maximum width for the article; &lt;code&gt;60ch&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We don’t need to go too much further to see that the number of characters is something we take into account when speaking about the width of an element. We can imagine this in the opposite direction, if the element is too small, the lines look smooshed. Here’s where we find the key insight. If we defined the width of an element using relative font units, and the user increases the font size, what happens? Think about it.&lt;/p&gt;
&lt;p&gt;Let’s use &lt;code&gt;30ch&lt;/code&gt; as a maximum width, which is approximately the &lt;code&gt;260px&lt;/code&gt; value from earlier, not counting the card padding using common font metrics for the body. As the user increases the font size, what &lt;code&gt;30ch&lt;/code&gt; means will &lt;em&gt;also increase&lt;/em&gt; as pixels. This means that the 30 characters will continue to be 30 characters, just larger in pixels. Visually, this would look like if we scaled the whole element up. This maintains the overall composition as the font size increases.&lt;/p&gt;
&lt;p&gt;On the other hand, if we used a &lt;code&gt;260px&lt;/code&gt; maximum width, the sheer size of large text would wrap too quickly, causing premature line wrapping because the pixels aren’t increasing with the size of the text. For this reason, I now recommend using relative font sizes, more specifically &lt;code&gt;(r)ch&lt;/code&gt; units, to define widths. That is, if you truly need to define a width at all. For me, the best case is to still avoid setting a width wherever possible and let the content dictate the size.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;Importantly, things about this are slightly different between large desktops and small touch screens. The expectation for larger screens is to reflow first before overflowing outside the viewport. It is reasonable for overflow to occur sooner on smaller devices due to the limited space but similar font size we’d expect a user to have between large and small devices.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;h2 id=&quot;breakpoints&quot;&gt;Breakpoints&lt;/h2&gt;
&lt;p&gt;The reason that I had the idea for this article is due to &lt;a href=&quot;https://www.linkedin.com/feed/update/urn:li:activity:7341362642747387905/&quot;&gt;this post on LinkedIn&lt;/a&gt; by Matthew Wood. He explains the advantage of using &lt;code&gt;(r)em&lt;/code&gt; for media and container queries. He outlines how the approach helps support specific articles within the WCAG, &lt;a href=&quot;https://yatil.net/blog/resize-text-reflow&quot;&gt;1.4.4 and 1.4.10&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Due to the common use of minimum and maximum widths in breakpoints, and our earlier exploration into the benefits of maintaining layout composition when using relative font units for this, I can agree that using relative font units for breakpoints would be preferred over pixel values. That is, if you need breakpoints at all.&lt;/p&gt;
&lt;p&gt;As I wrote years ago within &lt;a href=&quot;https://gridless.design/&quot;&gt;Gridless Design&lt;/a&gt;, the web was made to flow like a document. So if something doesn’t fit, the best way to handle it is to let the element wrap underneath. The more custom you want that behavior to be, the more difficult it is to appropriately handle how it is meant to behave for different user preferences and devices.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;In this article’s alternate reality, we’d discuss how defining &lt;code&gt;font-size&lt;/code&gt; should include fixed pixel amounts when working with fluid typography to observe the browser’s zoom feature. This is outlined in detail within &lt;a href=&quot;https://www.smashingmagazine.com/2023/11/addressing-accessibility-concerns-fluid-type/&quot;&gt;this article on Smashing Magazine&lt;/a&gt; by Maxwell Barvian.&lt;/p&gt;&lt;p&gt;And avoid setting the root font size. Let the user provide that, please.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;These are my new rules of thumb based on the earlier explorations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use fixed pixel units (&lt;code&gt;px&lt;/code&gt;) for spacing.&lt;/li&gt;
&lt;li&gt;Avoid setting dimensions wherever possible.&lt;/li&gt;
&lt;li&gt;If you must set a dimension, use font relative units (&lt;code&gt;(r)ch&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I wouldn’t consider these rigid, but I would refrain from deviating unless you truly understand why.&lt;/p&gt;
&lt;p&gt;And for heavens sake &lt;strong&gt;don’t make tokens for dimensions&lt;/strong&gt;. Dimensions are specific to the layout. This includes breakpoints because when the layout breaks isn’t due to being a specific device. It’s because the current composition visually &lt;em&gt;breaks&lt;/em&gt; at this &lt;em&gt;point&lt;/em&gt;. Unless you’re making tokens to define the parts of layout, avoid making tokens for dimensions.&lt;/p&gt;</content:encoded></item><item><title>The Hottest Box</title><link>https://blog.damato.design/posts/hottest-box</link><guid isPermaLink="true">https://blog.damato.design/posts/hottest-box</guid><pubDate>Mon, 16 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;Over the past year, I’ve had the task of creating layout components for an organization. This is something that was initially confused about. My initial assumption was that everyone knows about flexbox! It’s our lord and layout savior! Jokes about centering content should have vanished away now that we can use flexbox! Oh, how naïve I was.&lt;/p&gt;
&lt;p&gt;Realistically, the developer landscape doesn’t hone these skills well, and instead hides them behind APIs; even if &lt;a href=&quot;https://tailwindcss.com/docs/flex-direction&quot;&gt;those very APIs&lt;/a&gt; are identical to what a person would write in CSS. It’s true, &lt;a href=&quot;https://x.com/donniedamato/status/1831662438191612281&quot;&gt;people will do anything to avoid writing code in a &lt;code&gt;.css&lt;/code&gt; file&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Honestly, I stumbled all over making a robust layout component. The following is considerations I take into account and how I might build a new component if I was given another opportunity.&lt;/p&gt;
&lt;h2 id=&quot;layout&quot;&gt;Layout&lt;/h2&gt;
&lt;p&gt;The first thing I’d take into consideration is layout using flexbox. I’m avoiding introducing grid configurations here. I’ve found that in the years I’ve been working with CSS, grid is the lesser used layout technique. It certainly has benefits over flexbox in many cases, but the majority of layout needs revolve around aligning items on a single axis in a container.&lt;/p&gt;
&lt;p&gt;Much of the confusion about flexbox comes from the alignment properties; &lt;code&gt;align-items&lt;/code&gt; and &lt;code&gt;justify-content&lt;/code&gt;. They are very easy to get mixed up and, the results can be unexpected when you change the &lt;code&gt;flex-direction&lt;/code&gt;. I believe an improvement here would be to simplify the API.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;I’ll be using JSX syntax to describe the component API, but you could imagine similar configurations in your authoring experience of choice.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; stretch&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; stack&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;Hello world!&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first thing I’d introduce is the boolean properties of &lt;code&gt;stretch&lt;/code&gt; and &lt;code&gt;stack&lt;/code&gt;. The &lt;code&gt;stretch&lt;/code&gt; flag would switch between &lt;code&gt;inline-flex&lt;/code&gt; and &lt;code&gt;flex&lt;/code&gt; so the container can fill its parent. The &lt;code&gt;stack&lt;/code&gt; flag would toggle on &lt;code&gt;flex-direction: column&lt;/code&gt; so the children stack in a single column. I’d also include &lt;code&gt;wrap&lt;/code&gt; to align directly to &lt;code&gt;flex-wrap: wrap&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;With that out of the way, now we need to address the alignment properties. Generally, the expectation for someone manipulating layout is to place the content in one of 9 locations within the container. For example, take the following CSS:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    display&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; flex&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    align-items&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; start&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    justify-content&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; end&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This code will place the content in the top-right corner of an LTR container. But with one line of code, it’ll completely flip the position to the bottom-left corner:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;diff&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.box {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    display: flex;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-inserted)&quot;&gt;&lt;span style=&quot;user-select:none&quot;&gt;+&lt;/span&gt;   flex-direction: column;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    align-items: start;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    justify-content: end;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In my opinion, this is unexpected. The intention to show the items in a row versus a column shouldn’t have an effect on the alignment in this case. Instead, I’d like to see an approach where someone could configure the items such that the &lt;code&gt;stack&lt;/code&gt; has no effect.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;I’m aware that there are cases where we want the above behavior, such as when the writing mode is adjusted. I’d argue that this is rare in comparison to the task of creating layouts.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;Furthermore, I’d like to lean into &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_logical_properties_and_values&quot;&gt;CSS Logical Properties&lt;/a&gt;, such that configuration inputs have aliases; &lt;code&gt;left&lt;/code&gt; / &lt;code&gt;top&lt;/code&gt; would transform to &lt;code&gt;start&lt;/code&gt; and &lt;code&gt;right&lt;/code&gt; / &lt;code&gt;bottom&lt;/code&gt; transforms to &lt;code&gt;end&lt;/code&gt;, of course allowing these values directly as well. I could imagine some flag that turns off (eg., &lt;code&gt;logical=false&lt;/code&gt;) this translation &lt;a href=&quot;https://m2.material.io/design/usability/bidirectionality.html#mirroring-elements&quot;&gt;in cases where we want to force the direction regardless of the writing mode&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; logical&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{ &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; }&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    Media player timeline&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Importantly, we’d need to inform what axis to apply the &lt;code&gt;start&lt;/code&gt; or &lt;code&gt;end&lt;/code&gt;. Logical properties describe that the horizontal axis is the “inline” direction, and the vertical axis is the “block” direction. As we have seen, when we update the &lt;code&gt;flex-direction&lt;/code&gt;, these axes flip where I’d argue this is largely unexpected. So instead of using &lt;code&gt;align&lt;/code&gt; and &lt;code&gt;justify&lt;/code&gt;, I’d suggest &lt;code&gt;inline&lt;/code&gt; and &lt;code&gt;block&lt;/code&gt;, similar to how &lt;code&gt;padding&lt;/code&gt; and &lt;code&gt;margin&lt;/code&gt; would be modernly applied.&lt;/p&gt;
&lt;p&gt;With this all in mind, we’d have the following:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;    stack&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;    inline&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;left&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;    block&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;bottom&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    Hello world!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Regardless if the &lt;code&gt;stack&lt;/code&gt; was applied or not, the children of this LTR container would be placed in the bottom-left corner. In an RTL container, the items would be placed in the bottom-right corner because &lt;code&gt;logical&lt;/code&gt; defaults to &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The final element to consider here is handling the concept of “self”. The flexbox ecosystem allows an item to essentially override the placement given by the parent through properties such as &lt;code&gt;align-self&lt;/code&gt; and &lt;code&gt;justify-self&lt;/code&gt;. Knowing this, we can also see a potential problem with the current API. The words &lt;code&gt;inline&lt;/code&gt; and &lt;code&gt;block&lt;/code&gt; aren’t clear as to what they are affecting. A better API naming convention would be more clear about what these are doing. That is why the flexbox APIs include the words &lt;code&gt;items&lt;/code&gt; and &lt;code&gt;content&lt;/code&gt;; they are affecting the elements &lt;em&gt;inside&lt;/em&gt; this container, not the container itself.&lt;/p&gt;
&lt;p&gt;This means that we should have similar but separate APIs for the concept of affecting the elements inside versus the element itself. We can communicate that layout is affecting the interior children with &lt;code&gt;inset&lt;/code&gt; (ie., interior setup) and the exterior self with &lt;code&gt;outset&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;    inset&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{{ inline&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;start&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; block&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;end&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;    outset&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{{ &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;/* Similar options */&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; }}&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    Hello world!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We could also consider shorthands that handle these with a single value; affecting both &lt;code&gt;inline&lt;/code&gt; and &lt;code&gt;block&lt;/code&gt; in the same way. The following would place the text horizontally and vertically within the box:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; inset&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;center&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    Hello world!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;&lt;code&gt;inset&lt;/code&gt; means &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/inset&quot;&gt;something slightly different in CSS&lt;/a&gt; compared to how it is being used here. In CSS, the “in” is speaking about how the target is being set inside a parent element.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;One more thing to mention is the more nuianced alignment properties, such as &lt;code&gt;justify-content: space-between&lt;/code&gt;. Since we’re hiding implementation details to match some new expectations, I’d consider an option that would effectively override the given &lt;code&gt;inline&lt;/code&gt; or &lt;code&gt;block&lt;/code&gt; (depending on the &lt;code&gt;stack&lt;/code&gt; flag) to distribute the children.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; stack&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; inset&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;center&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; distribute&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;between&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;Child 1&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;Child 2&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;Child 3&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, the &lt;code&gt;justify-content&lt;/code&gt; would be set as &lt;code&gt;space-between&lt;/code&gt; instead of &lt;code&gt;center&lt;/code&gt;. I’m avoiding the word “space” here to not confuse with other spacing properties such as &lt;code&gt;padding&lt;/code&gt; or &lt;code&gt;gap&lt;/code&gt; which we’ll introduce later.&lt;/p&gt;
&lt;h2 id=&quot;appearance&quot;&gt;Appearance&lt;/h2&gt;
&lt;p&gt;By default, it makes sense to allow this container to be invisible when a configuration is omitted. This helps with general layout approaches, allowing boxes to be arranged without explicitly showing boundaries. However, in some cases we may want to have a box appear segregated from other boxes.&lt;/p&gt;
&lt;p&gt;Aligning with the idea of &lt;a href=&quot;https://mode.place&quot;&gt;Mise en Mode&lt;/a&gt;, appearance properties would be informed by the use of intents (ie., strict semantic tokens) where we’d consider the priority that this box is meant to convey. So the box with the highest priority would be presented in a way that was clear to a user that they should pay attention here first before looking at other elements. This suggests that there is a &lt;code&gt;priority&lt;/code&gt; setting that could either be numeric (&lt;code&gt;1&lt;/code&gt;, &lt;code&gt;2&lt;/code&gt;, &lt;code&gt;3&lt;/code&gt;, and so on) or Latinate ordinal numbers (&lt;code&gt;primary&lt;/code&gt;, &lt;code&gt;secondary&lt;/code&gt;, etc.). I’d recommend the latter and having only &lt;code&gt;default&lt;/code&gt;, &lt;code&gt;secondary&lt;/code&gt;, and &lt;code&gt;primary&lt;/code&gt;. This reduces the decision-making paralysis; making it more clear which to use. Having a number system of significant size makes it challenging to determine the most appropriate number. I also suggest using the term &lt;code&gt;default&lt;/code&gt; over including &lt;code&gt;tertiary&lt;/code&gt; as if you need an additional level, you can include it later.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;As a sidenote, you should never assign the primary concept of anything as the default. Primary should be reserved as the main focus for the user. Meanwhile, your default should be set as the most common presentation of any element. If primary is your most common presentation, that means nothing is really important because everything is important.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;Continuing with the Mise en Mode concept, this allows any box to present itself with any color combination as provided by the current mode. This means, if you need a purple gradient to convey the supreme intelligence of AI, you can do it by informing the intents with new values, not by providing new tokens directly to a component.&lt;/p&gt;
&lt;p&gt;I believe the priority of any box is more closely tied to the concept of surfaces. We could imagine that the &lt;code&gt;default&lt;/code&gt; priority to be the base level of the page where most UI elements would live. Next, the &lt;code&gt;secondary&lt;/code&gt; level could be reserved for elements that are meant to appear on top of the UI but are contextual to some anchor. You can think of flyouts like context menus or tooltips. These are introduced because there is some more important information for you to take in before continuing, but they aren’t typically the most important thing to do. Finally, the &lt;code&gt;primary&lt;/code&gt; level would be a full disruption like a modal, which is meant to appear on top of everything blocking further progress.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; aria-modal&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; inset&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;center&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; priority&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;primary&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;   Hello world!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Any one of these priorities would apply additional presentational styles to the element to allow it to convey the priority consistently. This is so our users can subconsciously learn the hierarchical order of the content and make better decisions.&lt;/p&gt;
&lt;h2 id=&quot;spacing&quot;&gt;Spacing&lt;/h2&gt;
&lt;p&gt;Continuing with Mise en Mode, more specifically its origins of &lt;a href=&quot;https://complementary.space/&quot;&gt;Complementary Space&lt;/a&gt;, I believe we’ll only need two spacing options for box: &lt;code&gt;padding&lt;/code&gt; and &lt;code&gt;gap&lt;/code&gt;. These would be &lt;em&gt;flags&lt;/em&gt; and not expecting values like T-shirt sizing. This is because the mode would inform the size.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-comment)&quot;&gt;/* Example 1 */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; padding&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; gap&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;Child 1&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;Child 2&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;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:var(--astro-code-token-comment)&quot;&gt;/* Example 2 */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; padding&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; gap&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; data-mode&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;density-shift&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;Child 1&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;Child 2&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;data-mode&lt;/code&gt; in the second example indicates that a mode changes occurs here. This would affect all intents of this element and below new values. The &lt;code&gt;density-shift&lt;/code&gt; value would refer to a mode that expects the density to shift down one level, such that &lt;code&gt;padding&lt;/code&gt; and &lt;code&gt;gap&lt;/code&gt; are smaller than if this mode wasn’t applied; as in the first example.&lt;/p&gt;
&lt;p&gt;You might consider simply adding &lt;code&gt;mode&lt;/code&gt; as the option instead. I’m specifically using &lt;code&gt;data-mode&lt;/code&gt; to indicate that this isn’t specific to &lt;code&gt;&amp;lt;Box/&amp;gt;&lt;/code&gt; but more related to Mise en Mode. If this element is meant to be the base of all other elements, then &lt;code&gt;mode&lt;/code&gt; could be appropriate.&lt;/p&gt;
&lt;p&gt;If Complementary Space is too radical of an idea, feel free to wade in the depths of applying T-shirt sizing values.&lt;/p&gt;
&lt;h2 id=&quot;loading&quot;&gt;Loading&lt;/h2&gt;
&lt;p&gt;Some work that was being done in parallel to the layout component was that of a skeleton loader. &lt;a href=&quot;https://component.gallery/components/skeleton/&quot;&gt;For many systems&lt;/a&gt;, this is a separate component than any others in the system for the specific purpose of displaying a placeholder while work is done in the background. This has the perception that the system is processing, as opposed to having a blank area waiting for content to appear.&lt;/p&gt;
&lt;p&gt;It was at this time that I realized that if the skeleton component represented content, and the box component was meant to arrange content, what if the box could represent placeholder content until it was provided? In other words, we can mark &lt;code&gt;&amp;lt;Box/&amp;gt;&lt;/code&gt; elements with an attribute that shows a skeleton loading presentation if the element has no content. Consider the following simple card layout:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; stack&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; padding&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; gap&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Media&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; src&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{ src } /&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; stack&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; padding&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; gap&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; data-mode&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;density-shift&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; standby&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;{ title }&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; standby&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;{ description }&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; standby&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;{ actions }&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Box&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;standby&lt;/code&gt; flag would show a skeleton loading presentation to elements if no content is provided. That could be done with the CSS &lt;code&gt;:empty&lt;/code&gt; selector.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;data-standby&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;:empty&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;    /* Skeleton loading presentation */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once content is added, the selector would no longer match and the skeleton styles would be removed through CSS. We could also consider being explicit about when the loader should be shown by using the value of &lt;code&gt;data-standby=&amp;quot;true&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;In a more complete system, there would exist &lt;code&gt;&amp;lt;Media/&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;Text/&amp;gt;&lt;/code&gt; components that would have more specific enhancements that aligned better for &lt;code&gt;standby&lt;/code&gt;, most likely inheriting from the foundational &lt;code&gt;&amp;lt;Box/&amp;gt;&lt;/code&gt;. For example, &lt;code&gt;&amp;lt;Media/&amp;gt;&lt;/code&gt; would have loading when no &lt;code&gt;src&lt;/code&gt; is provided (&lt;code&gt;:not([src])&lt;/code&gt;). &lt;code&gt;&amp;lt;Text/&amp;gt;&lt;/code&gt; would display skeleton lines instead of a single block, depending on the purpose of text. Titles could display a single line, while paragraphs could show 3.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;The purpose of embedding the ability to display a skeleton in any layout is powerful; assuming performance cannot be improved. This means that you can have a layout reused between the expected result and the lack of information with a single composition; just add content. No need to create a separate layout for when the content is missing and another for when the content is finally resolved.&lt;/p&gt;
&lt;h2 id=&quot;semantics&quot;&gt;Semantics&lt;/h2&gt;
&lt;p&gt;Something I’ve glossed over is how to assign the element that this component represents. In some systems, this is done with another prop that informs the HTML tag name to use (&lt;code&gt;&amp;lt;Box as=&amp;quot;section&amp;quot;/&amp;gt;&lt;/code&gt;). Instead, I’d recommend trying &lt;a href=&quot;https://github.com/framer/motion/blob/main/packages/framer-motion/src/components/utils/tag-proxy.ts#L16-L32&quot;&gt;a different approach&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;box.section&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    Hello world!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;box.section&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this way, it is more clear that the &lt;code&gt;section&lt;/code&gt; part of the element is related to the element that will be rendered. Using &lt;code&gt;as&lt;/code&gt; could be more ambiguous to what the prop is meant to do, such as the word &lt;code&gt;variant&lt;/code&gt;. You could also consider a more generic default export as &lt;code&gt;Box&lt;/code&gt; that refers to a simple &lt;code&gt;box.div&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;demo&quot;&gt;Demo&lt;/h2&gt;
&lt;p&gt;Here’s a demo of the concept, missing all the mode changing.&lt;/p&gt;
&lt;iframe height=&quot;500&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;The Hottest Box&quot; src=&quot;https://codepen.io/fauxserious/embed/PorvMEy?default-tab=js%2Cresult&amp;theme-id=light&quot; frameborder=&quot;no&quot; loading=&quot;lazy&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/fauxserious/pen/PorvMEy&quot;&gt;
The Hottest Box&lt;/a&gt; by Donnie D’Amato (&lt;a href=&quot;https://codepen.io/fauxserious&quot;&gt;@fauxserious&lt;/a&gt;)
on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;&lt;/iframe&gt;
&lt;hr/&gt;
&lt;p&gt;&lt;strong&gt;EDIT (2024-09-26):&lt;/strong&gt; &lt;a href=&quot;https://x.com/devongovett/status/1838980741197447529&quot;&gt;Devon Govett recently posted a similar approach&lt;/a&gt; where a &lt;code&gt;&amp;lt;Skeleton/&amp;gt;&lt;/code&gt; wrapper is added to &lt;em&gt;any&lt;/em&gt; component in the system which will cause media and text elements inside to shimmer. Based on what I’ve written above, of course I really resonate with this. I like how the wrapping component is the trigger because you can also add &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-busy&quot;&gt;accessibility attributes&lt;/a&gt; in there to markup the loading state within.&lt;/p&gt;
&lt;p&gt;There’s some feedback in the replies that challenges how the system is supposed to know what the content looks like. The fact is that we don’t need to know what the content looks like, we need to know what &lt;em&gt;kind&lt;/em&gt; of content it is.&lt;/p&gt;
&lt;p&gt;This is why thinking about design as intention over aesthetics is the key to systems thinking and how we could support this approach. For example, the intention for a heading is commonly for introducing a short concept or label. Therefore, the loading presentation for the area where a heading should appear could always be displayed as a single block instead of considering several lines. Certainly, it is entirely possible that the final content does create multiple lines however, the purpose of the skeleton is not to match one-for-one with the incoming content. It is meant to indicate perceived progress using a loose blueprint of the expected content.&lt;/p&gt;
&lt;p&gt;We already know the styles for the text that will appear once the content comes through, including the font size. We can use that font size to set the minimum height of the skeleton placeholder, perhaps using the new &lt;code&gt;lh&lt;/code&gt; unit. Also know that any styles that we use for the skeleton do not need to remain for when the content is applied. If the &lt;code&gt;lh&lt;/code&gt; unit isn’t appropriate for the incoming font, then no need to set a minimum height when the element is &lt;code&gt;:not(:empty)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For paragraphs, you can pick a number of lines to display when we expect a paragraph. You could even be more considerate and wire in a container query that changes the number of lines based on the size of the paragraph. Wider paragraph containers larger than &lt;code&gt;60ch&lt;/code&gt; in width can display 2 lines, while smaller widths can display 3. This could imitate line wrapping for the same repeatable placeholder content. This way, a paragraph in a loading hero section would show 2 lines, while a more narrow card would show 3 lines.&lt;/p&gt;
&lt;p&gt;The easiest one of these content elements to consider is the image or really any media. &lt;a href=&quot;https://www.smashingmagazine.com/2020/03/setting-height-width-images-important-again/&quot;&gt;Best practice for loading media&lt;/a&gt; is to set the dimensions in the HTML to help with content shifts which would clearly dictate the size of the container for the skeleton. In the event you couldn’t do this, you could have predetermined expectations for that media; square, 4:3, 16:9, and even a circle for avatars. These styles are already most likely applied to the media element already, so we shouldn’t need to use too much imagination about how this skeleton might look.&lt;/p&gt;</content:encoded></item><item><title>Hovercraft</title><link>https://blog.damato.design/posts/hovercraft</link><guid isPermaLink="true">https://blog.damato.design/posts/hovercraft</guid><pubDate>Thu, 24 Aug 2023 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;In a world where we apply personality to every little interaction for those sweet engagement metrics, the &lt;code&gt;:hover&lt;/code&gt; CSS pseudo selector is one of the easiest ways for folks to “make it pop”. However, I’ll argue that perhaps we don’t need to put so much design into it; at least from a token maintenance perspective.&lt;/p&gt;
&lt;h2 id=&quot;looking-good-feeling-good&quot;&gt;Looking good, feeling good&lt;/h2&gt;
&lt;p&gt;It is very common to have colors of a button change when a pointing device hovers over an interactive button. We often design for this because we’ve seen it before. It just &lt;em&gt;feels&lt;/em&gt; right. You could argue it might not look interactive if it didn’t respond to the incoming cursor. Even the default user-agent button has a hover effect, how could one possibly defend not including this effect?&lt;/p&gt;
&lt;p&gt;To start, let’s look at the default &lt;code&gt;&amp;lt;a/&amp;gt;&lt;/code&gt; element and how that behaves. You’ll notice that most user-agent defaults &lt;em&gt;don’t&lt;/em&gt; have any color change for the text. I’d theorize that there are two reasons for this. First, accessible text color is a challenge, especially when attempting to show a shade change on glyphs that are only a few pixels wide. This is the reason why most of the effects we decide to put on links are not color changes, but some other visual treatment like an underline visibility change or animation.&lt;/p&gt;
&lt;p&gt;The second reason is the foundation of my argument; the cursor changes when you hover on these elements.&lt;/p&gt;
&lt;p&gt;When a sighted user sees something they assume is interactive on screen, they’ll find the cursor and navigate it to the target. Once the cursor is in the interactive area of the target, it is common to provide feedback to the user that says &lt;em&gt;we are in an interactive area now, clicking here will do something&lt;/em&gt;. The cursor change on links is enough of a signifier to the user that you may interact with this special text.&lt;/p&gt;
&lt;p&gt;For the default user-agent &lt;code&gt;&amp;lt;button/&amp;gt;&lt;/code&gt; styles, the cursor &lt;em&gt;does not change&lt;/em&gt;. It remains the default arrow cursor.&lt;/p&gt;
&lt;h2 id=&quot;making-change&quot;&gt;Making change&lt;/h2&gt;
&lt;p&gt;The reason for the cursor difference on hover between links and buttons has some &lt;a href=&quot;https://ux.stackexchange.com/a/105098&quot;&gt;history&lt;/a&gt; and can be otherwise debated.&lt;/p&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://medium.com/simple-human/buttons-shouldnt-have-a-hand-cursor-b11e99ca374b&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;There’s a belief that the hand (pointer) cursor means clickable, but this is wrong and potentially problematic.&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://medium.com/simple-human/buttons-shouldnt-have-a-hand-cursor-b11e99ca374b&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;Adam Silver&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;p&gt;The issue with this statement is there’s nothing (past &lt;a href=&quot;https://www.w3.org/TR/css-ui-4/#valdef-cursor-pointer&quot;&gt;technical specifications&lt;/a&gt;) that tells daily users of the web the pointer cursor means you are hovering on a link. We have introduced the pattern of the cursor change for buttons, and for general interactivity, over time through shared expectations. This can be thought of as similar to the &lt;a href=&quot;https://www.nngroup.com/articles/hamburger-menus/&quot;&gt;hamburger menu&lt;/a&gt;, which originally meant nothing to most users but has been learned over time; even if other more verbose design patterns exist. The hamburger menu has become ubiquitous, as has the pointer on buttons.&lt;/p&gt;
&lt;p&gt;Due to this learning, I believe we could leverage the cursor change in the same way it has been done for links; the sole indicator of an interactive area awaiting your next move. That’s right, no color changes or fun 3D effects. Just a single pointer.&lt;/p&gt;
&lt;h2 id=&quot;form-follows-function&quot;&gt;Form follows function&lt;/h2&gt;
&lt;p&gt;If a user is confused about an interactive element being a link or button, it does not come down to the type of cursor chosen. The &lt;a href=&quot;https://css-tricks.com/buttons-vs-links/&quot;&gt;Button vs. Link&lt;/a&gt; debate is mostly rooted in resting visual preference. Users expect underlined text to behave like a link. While text elements with padding and colored backgrounds often behave as buttons. Our users have grown to identify these patterns through repeated experiences across dozens of sites per day.&lt;/p&gt;
&lt;p&gt;It would be beneficial to supply our users with expected experiences as any deviation can cause unwanted friction. A button using an underline and no padding will behave unexpectedly to a user, no matter how pretty it is. It is advised to offer sensible design treatments that maintain user expectations and common functionality.&lt;/p&gt;
&lt;p&gt;Importantly, users will often use their eyes to identify and develop their expectations before ever moving the mouse to the target. This happens before the cursor has the possibility of changing. They are quickly making assumptions about what the target can do, all before they ever get a chance to hover it. And for folks not using their eyes; they’ll never experience the effect at all.&lt;/p&gt;
&lt;h2 id=&quot;in-the-wild&quot;&gt;In the wild&lt;/h2&gt;
&lt;p&gt;I’ve gone through the 123 implementations of the &lt;a href=&quot;https://component.gallery/components/button/&quot;&gt;button component at the Component Gallery&lt;/a&gt;; how many of them don’t use the pointer on hover? 6; 4% of all buttons found on the site do not change the cursor on hover. While the &lt;a href=&quot;https://en.wikipedia.org/wiki/Bandwagon_effect&quot;&gt;Bandwagon effect&lt;/a&gt; can certainly be a factor, this is most likely from patterns forged from real-world use. Know that the first interactive area on the web was the link, so we have grown to expect the pointer to appear as an interactive identifier in other areas in turn.&lt;/p&gt;
&lt;h2 id=&quot;further-considerations&quot;&gt;Further considerations&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;For folks who aren’t using a mouse to navigate, they need focus styles. The hover effect might not ever be displayed to these users. As a more complete recommendation, focus styles between interactive elements should match so a user can follow a standard identifiable treatment across the site.&lt;/li&gt;
&lt;li&gt;For folks on touch devices, hover doesn’t exist except for some fleeting finger presses that occur &lt;em&gt;after&lt;/em&gt; the interaction. In most cases, a person’s finger will otherwise obscure the effect when provided.&lt;/li&gt;
&lt;li&gt;Using the cursor alone also avoids the need to curate specific colors for every type of button. No need to have a separate color for the default primary state and primary hover.&lt;/li&gt;
&lt;li&gt;For buttons that have a selected state; omitting separate styles for hovering helps avoid the need to define a different appearance between unselected hover and selected hover. Otherwise, the number of definitions will increase not only for &lt;code&gt;:hover&lt;/code&gt; but now include &lt;code&gt;[aria-selected=&amp;quot;true&amp;quot;]:hover&lt;/code&gt; for every single type of button in your library.&lt;/li&gt;
&lt;li&gt;In CSS, instead of specifically writing a &lt;code&gt;:hover&lt;/code&gt; style, the &lt;code&gt;cursor: pointer;&lt;/code&gt; can be written on the &lt;code&gt;button&lt;/code&gt; selector. No need for a new selector at all!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Consider a vote for &lt;code&gt;cursor:pointer&lt;/code&gt; today!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/vote-cursor-pointer.png&quot; alt=&quot;Political poster suggesting to use cursor:pointer&quot;/&gt;&lt;/p&gt;
&lt;h2 id=&quot;telling-the-truth&quot;&gt;Telling the truth&lt;/h2&gt;
&lt;p&gt;In reality, I don’t believe that a single cursor change is enough to indicate interactivity. A best practice of experience design is to have multiple signifiers to indicate new information. This is why using only color to indicate an error isn’t enough. It is better to include an icon to further enforce the status of the new message or state.&lt;/p&gt;
&lt;p&gt;In this way, instead of choosing an entirely new color to indicate hover, one recommendation could be filtering the given color in some way on hover.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;:hover&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    cursor&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; pointer&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    filter&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; saturate&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(0.8)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For many colors, a slight shift in saturation should not cause accessibility concerns past what has been curated for the default state. If this approach causes the resulting color to not provide enough contrast between the text and background, that might mean the initial color itself is too close to the threshold and would serve better with more contrast. On the other hand, if the change isn’t perceptable to color-deficient folks, the cursor will be enough to indicate the intention, as suggested above.&lt;/p&gt;
&lt;p&gt;In my perspective, there are often too many tokens to curate and anything that can be done to reduce the set and subsequent naming of additional tokens is a step in a maintainable direction. Omitting the hovered state as a themable variable helps reduce complexity and permutations.&lt;/p&gt;
&lt;p&gt;Perhaps, we need a new way of looking at the ecosystem.&lt;/p&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://twitter.com/markacianfrani/status/1694341251540123887&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;Design system business model where you have to pay for every token you use.&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://twitter.com/markacianfrani/status/1694341251540123887&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;Mark A. Cianfrani&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;p&gt;This isn’t the model we deserve, but it’s the one we need right now.&lt;/p&gt;</content:encoded></item><item><title>Interoperable tokens</title><link>https://blog.damato.design/posts/interoperable-tokens</link><guid isPermaLink="true">https://blog.damato.design/posts/interoperable-tokens</guid><pubDate>Thu, 16 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;In &lt;a href=&quot;https://system.damato.design&quot;&gt;my design system playground&lt;/a&gt;, one of my small goals was to have the ability to import a design token identically between CSS and JavaScript. Here’s an example of the developer experience I was expecting and succeed in making: to use &lt;code&gt;tokens.$action_primary_backgroundColor&lt;/code&gt; as a value reference in both &lt;code&gt;.scss&lt;/code&gt; and &lt;code&gt;.js&lt;/code&gt; files identically.&lt;/p&gt;
&lt;h3 id=&quot;writing-scss&quot;&gt;Writing (S)CSS.&lt;/h3&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;scss&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;@use&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;../tokens.module&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;:where&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;data-priority&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;primary&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    background-color&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; tokens.$action_primary_backgroundColor&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;writing-jsx&quot;&gt;Writing JS(X).&lt;/h3&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; tokens &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;./_tokens.module.scss&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; PrimaryButton&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(props) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        {&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;props}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        style&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{{ &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;            backgroundColor&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; tokens&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.$action_primary_backgroundColor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        }}/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The important part is that the intention of using the background color for primary buttons is shared between the CSS and the JavaScript. &lt;code&gt;tokens.$action_primary_backgroundColor&lt;/code&gt; is identical between these examples while being applied in different languages. This method helps reduce the context switching between writing CSS and writing JS to get the expected styling value.&lt;/p&gt;
&lt;h2 id=&quot;working-source&quot;&gt;Working source&lt;/h2&gt;
&lt;p&gt;I’ll cut to the chase, the following is a &lt;code&gt;_tokens.module.scss&lt;/code&gt; file that all the components have access to. &lt;a href=&quot;https://github.com/damato-design/system/blob/main/src/components/_tokens.module.scss&quot;&gt;Here’s the file I use in my system.&lt;/a&gt; You’ll want to generate this file based on how you create and manage tokens in your system. You should expect many, many more entries in this file than what is shown below. This example is only supporting &lt;code&gt;tokens.$some_token&lt;/code&gt; between &lt;code&gt;.scss&lt;/code&gt; and &lt;code&gt;.js&lt;/code&gt; files.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;scss&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;/** For .scss, $some_token does not need to match the --some_token  */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;$some_token&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(--some_token);&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:var(--astro-code-token-comment)&quot;&gt;/** For .js, the #{&amp;#39;$some_token&amp;#39;} needs match $some_token */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;:export {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    #{&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;$some_token&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; $some_token&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;As you might tell, there are some requirements to this in order for the DX to work well.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You’ll need to ensure that the CSS custom property &lt;code&gt;--some_token&lt;/code&gt; has a value and is present on each page such that &lt;code&gt;var(--some_token)&lt;/code&gt; is later resolved. You could opt to &lt;em&gt;not&lt;/em&gt; use a CSS custom property here if the value don’t change. However, if you have or plan to have dark mode in your system, then you don’t want to hardcode the values here.&lt;/li&gt;
&lt;li&gt;You’ll need to be using &lt;a href=&quot;https://github.com/css-modules/css-modules&quot;&gt;CSS modules&lt;/a&gt; to get the JS import working, using the &lt;code&gt;:export&lt;/code&gt; pseudo selector. Most JS frameworks support CSS modules with minimal configuration. The word &lt;code&gt;module&lt;/code&gt; in the file name is required for the CSS Modules processing to pick this up as a CSS Module, so it can be imported into &lt;code&gt;.js&lt;/code&gt; files.&lt;/li&gt;
&lt;li&gt;You’ll need to be using &lt;a href=&quot;https://sass-lang.com/&quot;&gt;SCSS&lt;/a&gt; to get the &lt;code&gt;@use&lt;/code&gt; and &lt;code&gt;$&lt;/code&gt; variable syntax working in your &lt;code&gt;.scss&lt;/code&gt; files. The leading &lt;code&gt;_&lt;/code&gt; in the file name &lt;code&gt;_tokens.module.scss&lt;/code&gt; is required for the &lt;code&gt;@use&lt;/code&gt; syntax to work. This will expose a &lt;code&gt;tokens&lt;/code&gt; key in the SCSS &lt;a href=&quot;https://sass-lang.com/documentation/at-rules/use/&quot;&gt;based on the file name&lt;/a&gt;. In other words, to get the &lt;code&gt;tokens.&lt;/code&gt; syntax in your files, your file name should start with &lt;code&gt;_tokens.&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;required-characters&quot;&gt;Required characters&lt;/h2&gt;
&lt;p&gt;There’s lots of token naming constructions out there that delimit the sections of the token. For this to work, the underscore (&lt;code&gt;_&lt;/code&gt;) is one of the only characters that will work between (S)CSS and JS.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The dot delimiter (&lt;code&gt;.&lt;/code&gt;) will not be valid in &lt;code&gt;.scss&lt;/code&gt; files.&lt;/li&gt;
&lt;li&gt;The hyphen delimiter (&lt;code&gt;-&lt;/code&gt;) will not be valid in &lt;code&gt;.js&lt;/code&gt; files.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When you generate the &lt;code&gt;_tokens.module.scss&lt;/code&gt; file, you’ll want to convert any delimiter to an underscore. As an example, if you have a token &lt;code&gt;button.primary.backgroundColor&lt;/code&gt;, you’ll want to prepare that as &lt;code&gt;button_primary_backgroundColor&lt;/code&gt; to be used in source files. This makes the name usable between &lt;code&gt;.scss&lt;/code&gt; and &lt;code&gt;.js&lt;/code&gt; files in an identical way.&lt;/p&gt;
&lt;p&gt;The leading &lt;code&gt;$&lt;/code&gt; is expected for the SCSS ecosystem to be used as a variable. This is carried over into the JS ecosystem for consistency.&lt;/p&gt;
&lt;p&gt;You can review the source of my system to find additional details:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/damato-design/system/blob/main/src/modes/_system.yml&quot;&gt;How I curate tokens with values in &lt;code&gt;.yaml&lt;/code&gt;.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/damato-design/system/blob/main/scripts/generate-module.js&quot;&gt;How I transform tokens to &lt;code&gt;_tokens.module.scss&lt;/code&gt;.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>Late start</title><link>https://blog.damato.design/posts/late-start</link><guid isPermaLink="true">https://blog.damato.design/posts/late-start</guid><pubDate>Thu, 11 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;I’ve been in the process of writing a book over the past year and the hardest part for me isn’t the writing, it’s the publishing. I’ve changed publishing systems a few times over the course of this work. I’ll most likely have a larger post speaking about the process later, but the current way that I’m expecting to prepare the book for publishing is with CSS. Yep, that’s right. Get your &lt;code&gt;@page&lt;/code&gt; styles ready!&lt;/p&gt;
&lt;p&gt;Getting the options that a more appropriate layout system like InDesign would have isn’t really possible in most browsers today. If I really wanted to lean into all of the features that CSS could have, I’d consider using &lt;a href=&quot;https://www.princexml.com/&quot;&gt;PrinceXML&lt;/a&gt;. Though as it stands right now, I think I’ll have a good book without it.&lt;/p&gt;
&lt;p&gt;That said, there was some really challenging constraints that I had to work through. One of those things was page numbers.&lt;/p&gt;
&lt;h2 id=&quot;meeting-expectations&quot;&gt;Meeting expectations&lt;/h2&gt;
&lt;p&gt;One of the cool things about CSS is the &lt;code&gt;counter()&lt;/code&gt; function. This acts a bit like using state in CSS in limited way. To explain, here’s what using state in React might look like:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-keyword)&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; MyCounter&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;count&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; setCount&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; useState&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; onClick&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{ &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;setCount&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(count &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;) }&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;            { count }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can effectively do the same thing in CSS. Here’s a basic setup with some comments that explain what each of these relate to:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-string-expression)&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;    /* const [count, setCount] = useState(0) */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    counter-reset&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; count&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-string-expression)&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;    /* setCount(count + 1) */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    counter-increment&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; count&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-string-expression)&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;::marker&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;    /* (print) count */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    content&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; counter&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(count)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One of the bigger differences is that the count increases when an element exists at a selector. I imagine we could get some interesting state machine stuff with selecting values from inputs. But that’s not what we’re after today. Instead, I want to delay the start of the numbers.&lt;/p&gt;
&lt;p&gt;If you open up a technical book, you’ll find that the page numbers don’t start right after your crack open the cover. There’s a few a pages that either don’t have numbers, or have a different counting system like lowercase Roman numerals. Doing this in React would be fairly easy, we can set the start of the counter to a negative number and only print the number if the value is larger than &lt;code&gt;0&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-keyword)&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; MyCounter&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;count&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; setCount&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; useState&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; onClick&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{ &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;setCount&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(count &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;) }&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;            { count &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; ?&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; count &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In CSS, we don’t have this fine-grained conditional logic just yet. There’s definitely ways to do some &lt;a href=&quot;https://css-tricks.com/using-absolute-value-sign-rounding-and-modulo-in-css-today/&quot;&gt;tricky operations&lt;/a&gt; and maybe there is a way to do it using some of the newer functions, but I found something that’s a little more appropriate when dealing with counters. The new &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/@counter-style&quot;&gt;&lt;code&gt;@counter-style&lt;/code&gt;&lt;/a&gt; at-rule.&lt;/p&gt;
&lt;h2 id=&quot;custom-counters&quot;&gt;Custom counters&lt;/h2&gt;
&lt;p&gt;CSS has had keywords that describe the method of counting for a long time. It’s the same way we’d often &lt;em&gt;remove&lt;/em&gt; the style from &lt;code&gt;&amp;lt;ul/&amp;gt;&lt;/code&gt; elements to drop the bullets for other presentations.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-string-expression)&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    list-style-type&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; none&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For something like a &lt;code&gt;&amp;lt;ol/&amp;gt;&lt;/code&gt; element, the &lt;code&gt;list-style-type&lt;/code&gt; is set as &lt;code&gt;decimal&lt;/code&gt;. You may also know that &lt;code&gt;&amp;lt;ol/&amp;gt;&lt;/code&gt; elements have a special &lt;code&gt;start&lt;/code&gt; property that allows us to start the count at a different number. Immediately, you’d think that we’d use that like our negative &lt;code&gt;setState(-3)&lt;/code&gt; from before. And while you can, it won’t work for my use case. Since I’m using &lt;code&gt;@page&lt;/code&gt; to display page numbers in print media, there’s no “element” for us to apply it to. That’s ok, CSS counters have a syntax that allow us to update the start for a counter and we can make it increment at each page.&lt;/p&gt;
&lt;p&gt;Here, I’m going to start the count at the first page, name the counter &lt;code&gt;page&lt;/code&gt;, and increment at every page:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-keyword)&quot;&gt;@page&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; :first&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    counter-reset&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; page -3&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;@page&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    counter-increment&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; page&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s a good start, but the problem is that the first page will print the number &lt;code&gt;-3&lt;/code&gt; at the bottom which is not what we’re looking for. Instead, I’d like these to be blank. To do this we’re going to need two &lt;code&gt;@counter-style&lt;/code&gt; declarations:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-keyword)&quot;&gt;@counter-style&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; false-start {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    system&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; extends decimal&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    range&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1 infinite&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    fallback&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; blank-only&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;@counter-style&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; blank-only {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    system&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; cyclic&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    symbols&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  ;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first &lt;code&gt;@counter-style&lt;/code&gt; has the name &lt;code&gt;false-start&lt;/code&gt; which extends the &lt;code&gt;decimal&lt;/code&gt; system which would normally be no different than the default &lt;code&gt;counter&lt;/code&gt;. However, the first key here is that the &lt;code&gt;range&lt;/code&gt; is set to &lt;code&gt;1 infinite&lt;/code&gt; which say to only use positive numbers starting at &lt;code&gt;1&lt;/code&gt;. When using &lt;code&gt;range&lt;/code&gt; you can also use a &lt;code&gt;fallback&lt;/code&gt; which says if the counter produces a number that cannot be written, use this style as a fallback.&lt;/p&gt;
&lt;p&gt;The second &lt;code&gt;@counter-style&lt;/code&gt; uses &lt;code&gt;system: cyclic;&lt;/code&gt; which is normally used to cycle through the given &lt;code&gt;symbols&lt;/code&gt;. In my case, I’ve provided whitespace. This means that when a negative number is passed into the counter, it will print whitespace. This allows me to set an offset and only print numbers starting at 1 exactly where I want them to start. Here’s the whole code using &lt;code&gt;@page&lt;/code&gt;, and a Codepen demonstrating it using &lt;code&gt;&amp;lt;li/&amp;gt;&lt;/code&gt; elements.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-keyword)&quot;&gt;@counter-style&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; false-start {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    system&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; extends decimal&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    range&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1 infinite&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    fallback&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; blank-only&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;@counter-style&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; blank-only {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    system&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; cyclic&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    symbols&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  ;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;@page&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    counter-increment&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; page&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;@page&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; :first&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    counter-reset&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; page -3&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;@page&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; :left&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;bottom-left-corner&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        content&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; counter&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(page&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; false-start)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;@page&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; :left&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;bottom-right-corner&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        content&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; counter&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(page&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; false-start)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;iframe height=&quot;500&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;Late start with @counter-style&quot; src=&quot;https://codepen.io/fauxserious/embed/WbQWdxw?default-tab=html%2Cresult&quot; frameborder=&quot;no&quot; loading=&quot;lazy&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/fauxserious/pen/WbQWdxw&quot;&gt;
Late start with @counter-style&lt;/a&gt; by Donnie D’Amato (&lt;a href=&quot;https://codepen.io/fauxserious&quot;&gt;@fauxserious&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;Sure, my use-case is very specific but maybe there’s someone else out there looking to write a book and not looking to learn a new language to do it.&lt;/p&gt;
&lt;p&gt;CSS is awesome and it could be awesomer. Rachel Andrew has &lt;a href=&quot;https://www.smashingmagazine.com/2015/01/designing-for-print-with-css/&quot;&gt;an article&lt;/a&gt; published over 10 years ago that outlines some of the other cool things that we could have.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-string-expression)&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  string-set&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; doctitle content(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;); &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What the hell is this? It’s taking the content of the &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt; and writing it into the &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; on the page! While I have no idea what this means for an accessible web page, this is meant for print and adding the content into the margins of the book. This ability of grabbing HTML content to use in CSS is incredible. It would open up a lot of possibilities (and poor behavior). There’s even a full &lt;code&gt;@footnote&lt;/code&gt; feature in there too.&lt;/p&gt;
&lt;p&gt;Unfortunately, these aren’t in any browsers today. I guess who is printing things anyway now that &lt;a href=&quot;https://www.nbcnews.com/tech/tech-news/federal-judge-rules-copyrighted-books-are-fair-use-ai-training-rcna214766&quot;&gt;the reading is done with AI&lt;/a&gt;? Silly me.&lt;/p&gt;</content:encoded></item><item><title>Less Gridless</title><link>https://blog.damato.design/posts/less-gridless</link><guid isPermaLink="true">https://blog.damato.design/posts/less-gridless</guid><pubDate>Wed, 09 Apr 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;I released &lt;a href=&quot;https://gridless.design&quot;&gt;Gridless Design&lt;/a&gt; nearly 4 years ago as a response to a frustration I saw in the industry. Similar to the desire for responsive design, it was a call for folks making digital applications to take the foundations on the web into consideration when creating things on top of it. It has the same foundational argument attached to “should designers code” because it asks designers to understand that the web is not an artboard. It also helps engineers support designs when a grid is no longer part of the handoff.&lt;/p&gt;
&lt;p&gt;Gridless Design was my first project that got a lot of discussion across the industry. Most leaders in our practice agreed with the take, while others with less experience were &lt;a href=&quot;/posts/feeding-trolls&quot;&gt;skeptical to say the least&lt;/a&gt;. I’ve had analytics tied to the site for a long time, and it continues to be a top performer among my other work. Some of the places that currently link to the work are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://utopia.fyi/&quot;&gt;Utopia.fyi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://css-irl.info/&quot;&gt;CSS IRL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://css-tricks.com/&quot;&gt;CSS-Tricks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bradfrost.com/&quot;&gt;Brad Frost&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://moderncss.dev/&quot;&gt;Modern CSS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is among other internal resource sites like Sharepoint and Jira. I’m glad the concept has gotten so popular. And that’s a bit about what this post is about. I think it’s time to sunset the site.&lt;/p&gt;
&lt;h2 id=&quot;grids-are-gone&quot;&gt;Grids are gone&lt;/h2&gt;
&lt;p&gt;4 years later, I can’t remember the last time I saw a design grid being shared amongst designers. Either externally on social media, or internally in product design teams. It would seem that the concept has either been very successful or other factors like responsivie design itself have made it more clear than Gridless Design as a goal could have done alone. Maybe the popularity of Tailwind which doesn’t use a design grid was another facet. Even AI could have been a factor.&lt;/p&gt;
&lt;p&gt;No matter the reason why the design grid has faded into the distance for digital design, that was the purpose for the site. It would seem it has fullfilled its purpose and now I can consider bringing it down.&lt;/p&gt;
&lt;p&gt;While I’ve been writing the book about &lt;a href=&quot;https://mode.place&quot;&gt;Mise en Mode&lt;/a&gt;, I’ve also considered what other topics would be good for a book. When I thought about Gridless Design being my first large work as a possibility, I considered how relevant it would be. This caused all of the reflection I’ve had in this post, which is leading me to this decision. Plus, it always helps to drop a domain that costs $50 per year from your account.&lt;/p&gt;
&lt;h2 id=&quot;whats-next&quot;&gt;What’s next&lt;/h2&gt;
&lt;p&gt;Gridless Design isn’t going away completely. It’s clear that the resource has been helpful to some people over the past few years and it could continue to be helpful for folks in years to come. So, here’s the plan:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Finish the book.&lt;/li&gt;
&lt;li&gt;Move &amp;amp; update the content to be hosted at one of my other main properties.&lt;/li&gt;
&lt;li&gt;Update the site explaining the move, include the new link.&lt;/li&gt;
&lt;li&gt;Let the site expire within the year after the site is updated.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Nothing is changing right now. The book is still the priority. Look out for the plan to take effect within the next year.&lt;/p&gt;
&lt;p&gt;It’s been fun getting rid of grid with you.&lt;/p&gt;</content:encoded></item><item><title>Logical Optical</title><link>https://blog.damato.design/posts/logical-optical</link><guid isPermaLink="true">https://blog.damato.design/posts/logical-optical</guid><pubDate>Thu, 27 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;I got into an argument on LinkedIn this week about design choices. Very on brand for me. It started with this image:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/questionable-alignment.jpg&quot; alt=&quot;Google logo isn&apos;t circular and pixel offsets for browser search bar&quot;/&gt;&lt;/p&gt;
&lt;p&gt;The post was defending the choices made in the image, and went on to say that people who aren’t designers have no business questioning these decisions. The weird part about it was that this person wasn’t a designer according to their profile. Since they’ve blocked me from rebutting I can’t link to the post, but I want to take the opportunity to explain that I understand why the logo is not truly a circle, but I’m less convinced about the bar in the field.&lt;/p&gt;
&lt;h2 id=&quot;the-fallacy-of-optical-alignment&quot;&gt;The fallacy of optical alignment&lt;/h2&gt;
&lt;p&gt;Much of my research is uncovering &lt;em&gt;why&lt;/em&gt; we make design decisions. This makes the decision repeatable by following some set of rules for when a new but understood pattern emerges. When it comes to optical alignment, there’s a large collection of articles made by designers who will explain that some shapes shouldn’t be mathematically centered, and instead should be “nudged” to make them look centered to the eye. I’ll be referencing some of the images from the &lt;a href=&quot;https://medium.com/ringcentral-ux/eyeballing-or-optical-alignment-in-design-4ef5ab2d326f&quot;&gt;very first post at the top of my search results for “optical alignment ui”&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is what we have typically called “optical centering”. And the post above even includes the word “eyeballing”. Here’s an example from the post but is also found in &lt;a href=&quot;https://marvelapp.com/blog/optical-adjustment-logic-vs-designers/&quot;&gt;many&lt;/a&gt; &lt;a href=&quot;https://railsdesigner.com/mathematical-optical-alignment-design/&quot;&gt;similar&lt;/a&gt; &lt;a href=&quot;https://www.linkedin.com/posts/ranausman7330_ui-ux-design-activity-7288418232661659648-6APb/&quot;&gt;articles&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/playbutton-offset.webp&quot; alt=&quot;Play button offset from mathematical center&quot;/&gt;&lt;/p&gt;
&lt;p&gt;When we measure the sides of the icon in the middle, they don’t match. However, the icon looks like its centered in the middle of the container. Is this just how our eyes work? Are our eyes imperfect? No, you are still centering the icon. It’s just using a different center. In fact, the triangle is a great example of &lt;a href=&quot;https://www.youtube.com/watch?v=v_oZ9Pe0yRg&quot;&gt;a shape that has lots of centers&lt;/a&gt;. Here’s an image from &lt;a href=&quot;https://medium.com/@wudaoooooo/the-play-button-is-not-optical-alignment-4cea11bda175&quot;&gt;another post&lt;/a&gt;, which demonstrates how this would work in a circular container:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/playbutton-incircle.webp&quot; alt=&quot;Play button offset from mathematical center&quot;/&gt;&lt;/p&gt;
&lt;p&gt;The post where that image is from also shows that the technique being described doesn’t necessarily work for all icons. All icons are not squares or triangles so how are we suppose to think of this? Let’s look at another example which is linked to optical alignment.&lt;/p&gt;
&lt;h2 id=&quot;area-not-dimension&quot;&gt;Area not dimension&lt;/h2&gt;
&lt;p&gt;Here’s another image from the first article:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/square-circle.webp&quot; alt=&quot;A square and a cirlce with the same height&quot;/&gt;&lt;/p&gt;
&lt;p&gt;The post explains that we need to increase the size of the circle because the square looks larger. However, the post doesn’t explain how much you are meant to increase it by. Is it until it LooksGood™? Even &lt;a href=&quot;https://medium.com/design-bridges/optical-effects-9fca82b4cd9a&quot;&gt;the post they’ve linked to&lt;/a&gt; doesn’t explain how to do it. The best suggestion is to blur the icon but that seems even less precise. So what’s the answer?&lt;/p&gt;
&lt;p&gt;The visual weight looks different between the square and circle of the same height because they &lt;em&gt;are&lt;/em&gt; different. What we actually want is shapes of a similar area. Here’s an image from &lt;a href=&quot;https://blog.kleinpixelagency.com/perfect-your-designs-with-imperfection-guide-to-optical-alignment-f76999b5d62d&quot;&gt;another post&lt;/a&gt; that discusses optical alignment:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/equal-area-shapes.webp&quot; alt=&quot;Square and cirlce of equal area showing visual balance&quot;/&gt;&lt;/p&gt;
&lt;p&gt;As you can see, we now have a repeatable process to help understand &lt;em&gt;why&lt;/em&gt; the circle is larger. In fact, we have created tools to help us with this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/keyline-grid.jpg&quot; alt=&quot;Material Design Keyline Grid&quot;/&gt;&lt;/p&gt;
&lt;p&gt;This is the keyline grid provided from &lt;a href=&quot;https://m2.material.io/design/iconography/system-icons.html#grid-and-keyline-shapes&quot;&gt;Google’s Material Design documentation&lt;/a&gt;. That’s right, the guy who wrote &lt;a href=&quot;https://gridless.design&quot;&gt;Gridless Design&lt;/a&gt; is recommending a grid as a tool. This is used to help designers draw icons with a consistent size and alignment. There’s more detail about how to use this grid at the documentation page.&lt;/p&gt;
&lt;p&gt;But let’s look deeper into this grid with our new found knowledge. Let’s measure the area of the main shapes provided by the grid. If we count the number of grid squares we should get an approximation for the area of the circle found within the keylines using the following formula for a circle:&lt;/p&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.css&quot; integrity=&quot;sha384-WsHMgfkABRyG494OmuiNmkAOk8nhO1qE+Y6wns6v+EoNoTNxrWxYpl5ZYWFOLPCM&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;π&lt;/mi&gt;&lt;msup&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msup&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;π&lt;/mi&gt;&lt;mn&gt;100&lt;/mn&gt;&lt;mo&gt;≈&lt;/mo&gt;&lt;mn&gt;314&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\pi r^2= \pi 100 \approx 314&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8141em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;π&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.02778em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8141em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;π&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;≈&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;314&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;So 314 grid units is our approximation for the area of the circle. Now let’s check the area of the square found within the keylines:&lt;/p&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.css&quot; integrity=&quot;sha384-WsHMgfkABRyG494OmuiNmkAOk8nhO1qE+Y6wns6v+EoNoTNxrWxYpl5ZYWFOLPCM&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msup&gt;&lt;mi&gt;w&lt;/mi&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msup&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msup&gt;&lt;mn&gt;18&lt;/mn&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msup&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;324&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;w^2= 18^2= 324&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8141em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.02691em;&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8141em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8141em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8141em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;324&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Is this the best we can do for the grid? Let’s check where the width is a smaller or larger grid:&lt;/p&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.css&quot; integrity=&quot;sha384-WsHMgfkABRyG494OmuiNmkAOk8nhO1qE+Y6wns6v+EoNoTNxrWxYpl5ZYWFOLPCM&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msup&gt;&lt;mi&gt;w&lt;/mi&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msup&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msup&gt;&lt;mn&gt;16&lt;/mn&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msup&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;256&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;w^2= 16^2= 256&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8141em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.02691em;&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8141em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8141em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8141em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;256&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.css&quot; integrity=&quot;sha384-WsHMgfkABRyG494OmuiNmkAOk8nhO1qE+Y6wns6v+EoNoTNxrWxYpl5ZYWFOLPCM&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msup&gt;&lt;mi&gt;w&lt;/mi&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msup&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msup&gt;&lt;mn&gt;20&lt;/mn&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msup&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;400&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;w^2= 20^2= 400&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8141em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.02691em;&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8141em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8141em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8141em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;400&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;We can see that this is the closest we can get to have the circle and square match in area. Only off by about 10 grid units. With a higher fidelity grid, we could get even more precise. But the bottom line here is that we’re trying to make shapes of equal area when we are “optically” sizing these elements. That’s why this grid is recommended and why it works.&lt;/p&gt;
&lt;p&gt;Math isn’t being thrown out the window in favor of design, most people are using the wrong math.&lt;/p&gt;
&lt;h2 id=&quot;circling-back&quot;&gt;Circling back&lt;/h2&gt;
&lt;p&gt;Returning to the image that started it all. I’m not a typographer, so I’m under qualified to speak about how to adjust the G in the logo so it LooksGood™. And in reply to the post, I said that right now I’d chalk it up to pure brand personality. I have confidence there are qualities of typographic glyphs that follow some of the thinking I’ve demonstrated here but I don’t know precisely how they relate so I won’t comment on it now.&lt;/p&gt;
&lt;p&gt;However, that bar in the search field. I can’t agree with that. And it’s true I’ve never noticed it before, and often times when I’m just navigating around a user-interface I don’t notice things that are off by a few pixels. This isn’t because I’m not a designer (though I do consider myself one), this is because I’m not spending the amount of time staring at a user interface decision to care about what went into it. Only unless it looks out of place while I’m using it does it catch my eye and these few pixels weren’t enough to stop me.&lt;/p&gt;
&lt;p&gt;This describes one of the largest biases in our work, staring at it for too long. In the best case scenario, the user doesn’t remember &lt;em&gt;anything&lt;/em&gt; about your work. They got the task done, and they moved on with life. The amount of time some of industry spends staring at the details can be wasteful in the grand opera of user experience. So if the space between top and bottom of this bar was deliberate, I’m not confident many people would have noticed unless you had the time to stare at it.&lt;/p&gt;
&lt;p&gt;But since we’re looking at it, let’s talk about it. Or rather, let’s talk about another search bar that the original author shared in the comments: &lt;a href=&quot;https://atlassian.design&quot;&gt;Atlassian’s search bar&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/atlassian-search.jpeg&quot; alt=&quot;Atlassian search bar&quot;/&gt;&lt;/p&gt;
&lt;p&gt;The original poster argued that if Atlassian is also misaligning their icons that it all must be some conspiricy against proper alignment techniques. That response is an exaggeration instead of taking a moment to think &lt;em&gt;why&lt;/em&gt; they could have done this. Let’s look at a few things by making some lines and pixel measurements.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/atlassian-search-lines.png&quot; alt=&quot;Atlassian search bar with grid lines&quot;/&gt;&lt;/p&gt;
&lt;p&gt;One of the first things we can see is that there &lt;em&gt;is&lt;/em&gt; alignment. The team may have chose to align the icon to the baseline of the text. The next thing we can see is that it would seem that the text isn’t truly centered within the frame. Is that intentional? No, at least not in the way the web designers were expecting it to happen. We can see what’s happening when we inspect the box in devtools.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/atlassian-search-boxmodel.png&quot; alt=&quot;Atlassian search bar box model&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Measuring by eye in my editor isn’t getting me perfect results! What gives? This is most likely due to how the font sits within the line-height box. There’s &lt;a href=&quot;https://iamvdo.me/en/blog/css-font-metrics-line-height-and-vertical-align&quot;&gt;a great post about this&lt;/a&gt; if you want to dive into it. But what’s most likely happening is that the font doesn’t sit in the vertical center of the &lt;code&gt;24px&lt;/code&gt; line height box, which causes the space on top to be larger than the bottom. If this was a custom font provided by Atlassian, they would be in control of how the font sits in this box. However, they’ve chosen to use &lt;code&gt;ui-sans-serif&lt;/code&gt; which will use the current font of the operating system the user is using. So they have no real control about which font that is or how that font sits in the line height box.&lt;/p&gt;
&lt;p&gt;Back to the icon, if we continue inspecting, we’ll find that the icon is &lt;em&gt;not&lt;/em&gt; found within a perfect square even though the icon width and height are declared identically.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/atlassian-search-iconsize.png&quot; alt=&quot;Atlassian search bar icon sizing&quot;/&gt;&lt;/p&gt;
&lt;p&gt;How could this be intentional if the size is declared as &lt;code&gt;24&lt;/code&gt; but not rendering as 24? In my opinion, this wasn’t intentional. The fact is that the amount of difference between the rendering and the intented size is so slight that it wouldn’t matter to look into it further. The icon LooksGood™ so we ship it. In this case, it’s doing the job so it’s fine to move on to something else.&lt;/p&gt;
&lt;p&gt;However, if they really wanted to make the icon a 24x24 square, it’s only a matter of adding &lt;code&gt;flex-shrink: 0&lt;/code&gt; to the direct child of the flex container holding the icon and the input elements. This is a common rule &lt;a href=&quot;https://github.com/damato-design/system/blob/main/src/components/Icon/styles.module.scss#L17&quot;&gt;I tend to put on my icon elements&lt;/a&gt; when they appear in flex containers because they can be easily squished. The &lt;code&gt;flex-shrink: 0&lt;/code&gt; tells the &lt;code&gt;&amp;lt;svg/&amp;gt;&lt;/code&gt; that it shouldn’t be affected by siblings that are growing to take up space.&lt;/p&gt;
&lt;p&gt;As for centering to the baseline, this could be intentional or it could just be an artifact of the elements used to compose this component. The element being used to hold the icon is a &lt;code&gt;&amp;lt;span/&amp;gt;&lt;/code&gt; element which is classified as an inline element so it behaves like text. This means its size can be affected by line height among other properties. If we were to change this to &lt;code&gt;display: flex&lt;/code&gt; (or even &lt;code&gt;inline-flex&lt;/code&gt;), then the box doesn’t behave like an inline element anymore because the flex algorithm takes precedence. Making that change, along with the earlier &lt;code&gt;flex-shrink: 0&lt;/code&gt; change on this element inside the current flex container set with &lt;code&gt;align-items: center&lt;/code&gt; would vertically align the icon and text as best as the CSS algorithm can do.&lt;/p&gt;
&lt;p&gt;Whether or not these decisions were deliberate or oversights, I can’t tell from the outside. Only the author of the component could disclose that. We’d always like to think these large companies are making choices intentionally but in reality there’s often so much going on with not enough resources that it’s often a matter of being good enough. &lt;a href=&quot;/posts/close-thy-enemy/&quot;&gt;I’ve found other areas&lt;/a&gt; where improvements could be made but you have to weigh the effort over the impact. Does it really matter if the icon isn’t perfectly centered? Will the user care or will it stop them from proceeding?&lt;/p&gt;
&lt;h2 id=&quot;space-bar&quot;&gt;Space bar&lt;/h2&gt;
&lt;p&gt;So when it comes to the bar in the original image, my best guess there isn’t that it was planned to line up with the icons outside of the search bar, since that is against &lt;a href=&quot;https://lawsofux.com/law-of-proximity/&quot;&gt;Gestalt’s law of proximity&lt;/a&gt;. It’s more likely that it was an unnoticed few pixels in an otherwise good enough to ship component. If they actually do line up with the icons outside, I think that’s more serendipitous than meticulous. Die-hard designers can justify this all they want with “known design principles” but I find understanding &lt;em&gt;why&lt;/em&gt; to be more powerful and harder to refute. Since no one but the original implementer could tell us, all folks tend to do is assume that it was intentional because this is a big company. As we now know this doesn’t need to be the only story.&lt;/p&gt;
&lt;p&gt;The point here is that you shouldn’t just take what other folks have said as gospel, especially in the case of design at large organizations. Challenging the norms is how we get innovation as long as we explain the reasoning behind what we do. When you explain those repeatable reasons, you are more likely to gain agreement than through trying to convey your feelings. The difficulty here is that we cannot itemize every single decision we make in design, especially in the production environments of building products. In many cases, we just need to get the proof of concept out the door and good enough for the next round of funding. That’s why we hear so many cases of poor accessibility, performance, and personalization in the majority of experiences. We have no time to explain why, it needs to be out yesterday. We have no time to fix it when we find out it could be improved, we have another priority. That gets repeated by other smaller organizations hoping that the big dogs did it well and that’s how we get bad patterns, &lt;a href=&quot;https://medium.com/google-design/the-evolution-of-material-designs-text-fields-603688b3fe03&quot;&gt;like floating labels&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And when a design systems architect tells you they have experience in this topic, blocking them from the conversation really emphasizes how much your argument LooksGood™. 😏&lt;/p&gt;</content:encoded></item><item><title>Low inspectations</title><link>https://blog.damato.design/posts/low-inspectations</link><guid isPermaLink="true">https://blog.damato.design/posts/low-inspectations</guid><pubDate>Wed, 01 Mar 2023 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;The design hand-off process is often troublesome because of intentions lost in translation. We’ve created &lt;a href=&quot;/posts/terminal-career&quot;&gt;expertise in this space between design and engineering&lt;/a&gt; to help smooth the exercise but we often try to find ways to bridge the gap without human intervention. One of these ways is generating resources to use from the design tool.&lt;/p&gt;
&lt;p&gt;I saw a great &lt;a href=&quot;https://www.youtube.com/watch?v=hbN9RGcQFNU&quot;&gt;Figma for developers video&lt;/a&gt; &lt;a href=&quot;https://twitter.com/megaroeny/status/1625680821372739586&quot;&gt;shared on social media&lt;/a&gt; last month. This is definitely a part of the role that isn’t often taught, leaving most engineers stumbling around the interface. There’s a lot of helpful points made in the short presentation but I need to be critical about one area in particular; the inspect panel.&lt;/p&gt;
&lt;h2 id=&quot;proceed-with-caution&quot;&gt;Proceed with caution&lt;/h2&gt;
&lt;p&gt;I consider the inspect panel to be a trap. Admittedly, calling it a trap is dramatic but it’s also meant to warn folks who accept what the panel provides verbatim; possibly believing it’s the blessed approach. I’ll be referring to &lt;a href=&quot;https://help.figma.com/hc/en-us/articles/360055203533-Use-the-Inspect-panel&quot;&gt;Figma’s inspect panel&lt;/a&gt; in the following examples as the most popular tool to date but any design tool feature that claims to output code should be treated with skepticism.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;This can exclude design tools that manipulate coded assets such as &lt;a href=&quot;https://www.framer.com/&quot;&gt;Framer&lt;/a&gt;. Because those assets are foundationally engineered, inspecting or exporting these is looking at the direct source code of the asset and not an estimated representation.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;h3 id=&quot;coordinate-system&quot;&gt;Coordinate system&lt;/h3&gt;
&lt;p&gt;Figma, like many design tools, place assets on a coordinate system. Elements are added to the artboard and positioned relatively to the top-left corner. This isn’t native to web layout, which works as a document where elements added are positioned relative to each other. DOM elements are situationally-aware of their ancestors and siblings to adjust their position. Could you change the positioning strategy for web elements? Yes, but you’ll have a much harder time getting them to be accessible and responsive when you break out of the native document flow. Until design tools present the web using native alignment, developers will be left to intepret what a fixed coordinate system should do within document flow. The auto-layout concepts gets us to begin crossing this bridge but we’re not entirely on the other side yet.&lt;/p&gt;
&lt;p&gt;💡 Shy from properties that update or declare the explicit position of an element such as &lt;code&gt;position&lt;/code&gt;, &lt;code&gt;top&lt;/code&gt;, and &lt;code&gt;left&lt;/code&gt;. Consider using modern CSS techniques like &lt;code&gt;display: flex;&lt;/code&gt; to place the element in the preferred location. Work with the designer to learn about the intentions between different user and device preferences.&lt;/p&gt;
&lt;h3 id=&quot;hyper-local-font-styles&quot;&gt;Hyper local font styles&lt;/h3&gt;
&lt;p&gt;Another feature of the web is that text styles cascade down to lower elements. You don’t need to explicitly provide the text styles at every bit of copy. Especially if you &lt;a href=&quot;https://gtmetrix.com/blog/dont-use-too-many-web-fonts/&quot;&gt;limit the number of fonts to improve performance&lt;/a&gt;. If you set the font styles for body copy on the &lt;code&gt;&amp;lt;body/&amp;gt;&lt;/code&gt; element, you don’t need to reduplicate the font definition at the element which contains the copy. Unfortunately, Figma provides text styles for every individual bit of copy in the artboard. While you can be sure that this bit of text will get the styles when you copy from the inspect panel; you could optimize for less CSS by setting the appropriate style higher in the cascade. This is also great for when you need to update the font styles globally.&lt;/p&gt;
&lt;p&gt;💡 Set the font properties higher up (like at the &lt;code&gt;&amp;lt;body/&amp;gt;&lt;/code&gt;) to allow the natural cascade to inform lower elements. Only update the property at the location where it doesn’t match with the cascade.&lt;/p&gt;
&lt;h3 id=&quot;missing-units&quot;&gt;Missing units&lt;/h3&gt;
&lt;p&gt;Figma and other design tools that claim they are for web design do not have web units. &lt;a href=&quot;/posts/62-5&quot;&gt;The &lt;code&gt;rem&lt;/code&gt; unit is particularly important on the web&lt;/a&gt;, but other units like percentage are also valuable when communicating layouts. Just watch out for &lt;a href=&quot;https://css-tricks.com/magic-numbers-in-css/&quot;&gt;magic numbers&lt;/a&gt;. The inspect panel is notorious for displaying verbose &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; values in pixels. &lt;a href=&quot;https://youtu.be/nYyFf-97Qqg?t=118&quot;&gt;Expert CSS authors will tell you&lt;/a&gt; that applying these as given in your code is bad practice. We’d rather allow the content to dictate the size of the container or base the dimensions off of some other relative proportion so every container is flexible to any content.&lt;/p&gt;
&lt;p&gt;💡 Ignore &lt;code&gt;height&lt;/code&gt; and &lt;code&gt;width&lt;/code&gt; properties when found and let the content determine how large the container should be. Consider &lt;code&gt;max-width&lt;/code&gt; or &lt;code&gt;max-height&lt;/code&gt; for large composition constraints. Work with the designer to determine what web units would work best in areas where they are needed. Avoid using pixels units for layout properties. Using pixels for decorative elements might be appropriate (ie. &lt;code&gt;border-width&lt;/code&gt;).&lt;/p&gt;
&lt;h3 id=&quot;miscellaneous&quot;&gt;Miscellaneous&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/box-sizing&quot;&gt;&lt;code&gt;box-sizing&lt;/code&gt;&lt;/a&gt;: Hopefully this is already found higher in the cascade and &lt;a href=&quot;https://andy-bell.co.uk/how-the-css-box-sizing-property-works/&quot;&gt;applied globally as &lt;code&gt;border-box&lt;/code&gt;&lt;/a&gt;. This is what &lt;a href=&quot;https://wiki.csswg.org/ideas/mistakes&quot;&gt;it should have been by default&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/isolation&quot;&gt;&lt;code&gt;isolation&lt;/code&gt;&lt;/a&gt;: This property creates a new &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/Stacking_context&quot;&gt;stacking context&lt;/a&gt; and you most likely won’t need to apply this property when you see it in the panel. For more information on stacking contexts and when they are helpful, I recommend &lt;a href=&quot;https://www.joshwcomeau.com/css/stacking-contexts/&quot;&gt;Josh W. Comeau’s article&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/order&quot;&gt;&lt;code&gt;order&lt;/code&gt;&lt;/a&gt;: This property should be avoided. While it can change the order of elements as they are displayed visually, &lt;a href=&quot;https://adrianroselli.com/2015/09/source-order-matters.html&quot;&gt;the HTML won’t match&lt;/a&gt;. Change the layout order as HTML instead of this property.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/overflow&quot;&gt;&lt;code&gt;overflow&lt;/code&gt;&lt;/a&gt;: You should reserve this property to create a scrollable containers. Setting overflow past this reason will cause clipping in containers and other side-effects; such as creating a new &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Block_formatting_context&quot;&gt;block-formatting context&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/z-index&quot;&gt;&lt;code&gt;z-index&lt;/code&gt;&lt;/a&gt;: You should try to avoid setting this property, especially in the case of considering a larger elevation system where collisions are unavoidable. For more information on why &lt;code&gt;z-index&lt;/code&gt; should be considered an escape-hatch, I recommend &lt;a href=&quot;https://www.joshwcomeau.com/css/stacking-contexts/&quot;&gt;Josh W. Comeau’s article&lt;/a&gt;. Yes, I’ve linked it twice in one post; it’s that important.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;stop-collaborate-and-listen&quot;&gt;Stop, collaborate, and listen&lt;/h2&gt;
&lt;p&gt;Ultimately, your developer should be empowered to provide feedback on the design. Likewise, the developer shouldn’t depend on what the expect panel presents as perfectly appropriate. There is an expertise in translation that must occur which only comes with practice and experience. Work together towards finding the best execution of the intended design. Dare I say, even &lt;a href=&quot;https://vimeo.com/296790002&quot;&gt;include them in the process&lt;/a&gt;. This can be the start of a beautiful partnership.&lt;/p&gt;</content:encoded></item><item><title>Meaningless curves ahead</title><link>https://blog.damato.design/posts/meaningless-curves</link><guid isPermaLink="true">https://blog.damato.design/posts/meaningless-curves</guid><pubDate>Tue, 07 Feb 2023 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;The tiered system of design tokens has been fairly well-established to include &lt;a href=&quot;/posts/tokens-as-intents&quot;&gt;semantic tokens&lt;/a&gt;. Color, typography, and even &lt;a href=&quot;https://complementary.space&quot;&gt;spacing&lt;/a&gt; can be described through semantic means. This drives the question, how do we name other properties semantically to further describe a generic experience?&lt;/p&gt;
&lt;h2 id=&quot;nested-rounding&quot;&gt;Nested rounding&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://cloudfour.com/thinks/the-math-behind-nesting-rounded-corners/&quot;&gt;This article at Cloud Four&lt;/a&gt; goes into the idea of nested rounding in detail. Essentially, we want the radius on rounded corners between nested elements to follow a shared focus (ie., center of a circle). The math is very simple, here it is using CSS notation:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.child&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    border-radius&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--ancestor-element-radius) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--distance-from-ancestor)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    )&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ultimately, we’d like to think of rounding in terms of semantics. However, because we want the rounding to be derived from elements, &lt;em&gt;we can avoid semantics entirely&lt;/em&gt;. In practice, the reason we might use semantics is when we have decisions to make that are more complicated than just on/off. Semantics are used to describe the why we chose this value from a plethora of other possible values. In our rounding treatment, we shouldn’t have more than one value. It should be a binary decision to include rounding or not and let other factors determine how round to achieve the nesting effect.&lt;/p&gt;
&lt;p&gt;In other words, when curating an experience, we’d like to &lt;strong&gt;simply mark elements which should receive nested rounding&lt;/strong&gt;. Later, we provide some themable amount used by the rounding calculation which affects the rounding of marked elements in a uniform manner. We do not prescribe the rounding amount at any one element explicitly, we simply expect the appropriate nested rounding to exist when turned on.&lt;/p&gt;
&lt;p&gt;However, we have some problems to try and overcome.&lt;/p&gt;
&lt;h2 id=&quot;deriving-values&quot;&gt;Deriving values&lt;/h2&gt;
&lt;p&gt;The first problem is trying to get the &lt;code&gt;--ancestor-element-radius&lt;/code&gt; and &lt;code&gt;--distance-from-ancestor&lt;/code&gt; values for the formula. The ancestor part provides a clue to what makes this so difficult. &lt;strong&gt;The nested rounding calculation is dependent on the relationship between &lt;em&gt;two&lt;/em&gt; elements.&lt;/strong&gt; This is different from a &lt;a href=&quot;/posts/spacing-solved&quot;&gt;semantic spacing approach&lt;/a&gt; as we only select a spacing token to convey a relationship. In the rounding formula, the final value is computed &lt;em&gt;using the resulting relationship&lt;/em&gt; when the rounding is meant to be applied.&lt;/p&gt;
&lt;p&gt;When trying to fill the &lt;code&gt;--distance-from-ancestor&lt;/code&gt; value, it’s very likely that we will have several elements nested which may or may not include their own methods of supplying space. The properties of &lt;code&gt;margin&lt;/code&gt;, &lt;code&gt;padding&lt;/code&gt;, &lt;code&gt;gap&lt;/code&gt;, and additional &lt;code&gt;position&lt;/code&gt; and &lt;code&gt;transform&lt;/code&gt; properties can all have a hand at visually presenting how far two elements are from each other, thereby making the &lt;code&gt;--distance-from-ancestor&lt;/code&gt; value very challenging to determine.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;You could try computing this in JavaScript. You’d mark elements that you’d like to measure between and then write the value to a CSS Custom Property. There’s a few pitfalls here; responsive changes, transforms, relative units, etc.. All of these things would make trying to capture this value a nightmare. This isn’t a simple programmatic redlining exercise. On top of this, adding JavaScript to adjust a visual treatment seems like a bad use of the main thread. &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers&quot;&gt;Web Workers&lt;/a&gt; for &lt;code&gt;border-radius&lt;/code&gt;? Now that’s just crazy talk.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;Let’s assume we have a system which can readily provide the &lt;code&gt;--distance-from-ancestor&lt;/code&gt;. The &lt;code&gt;--ancestor-element-radius&lt;/code&gt; in a perfect system would also be derived by the formula. So where does the base radius come from that influences all other nested rounding? Would it make sense for the &lt;code&gt;&amp;lt;body/&amp;gt;&lt;/code&gt; to declare the first amount of rounding? Conceptually this seems incorrect since we don’t expect the &lt;code&gt;&amp;lt;body/&amp;gt;&lt;/code&gt; element to have rounding at all. Though, we can simply choose not to apply rounding at the &lt;code&gt;&amp;lt;body/&amp;gt;&lt;/code&gt; and rather only define the value here.&lt;/p&gt;
&lt;p&gt;Another problem with starting from the top would be that some elements would never receive rounding. If you have a button which expects rounding to appear in two different places, it is possible that they receive different rounding amounts based on how many nested ancestors are marked for rounding between them. This could cause the same button to look different just by its placement within the layout.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/rounding-top-down.png&quot; alt=&quot;Content without rounding prescribes non-rounded button, content with rounding prescribes rounded button.&quot;/&gt;&lt;/p&gt;
&lt;p&gt;So, instead of starting at the top, could we start at the bottom? That is, could we declare what the smallest rounding is and then have marked ancestor elements use that value? After all, the center of the radius that determines the rounding must exist inside this element. Perhaps a new calculation would look like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.parent&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    border-radius&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--deepest-element-radius) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--distance-from-deepest)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    )&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this way, the &lt;code&gt;--deepest-element-radius&lt;/code&gt; can now be a fixed number, provided by a theme because there should be no smaller rounding applied. All rounding that occurs above this element is derived from this base amount. For the purposes of our exploration, let’s call these deepest elements the &lt;strong&gt;rounding focus&lt;/strong&gt;, as they possess the center which all ancestor element rounding radii would be computed in this system.&lt;/p&gt;
&lt;p&gt;The logic within marked ancestor elements would identify their deepest rounding focus and calculate the distance between their bounding boxes to determine the &lt;code&gt;--distance-from-ancestor&lt;/code&gt;. We already know the difficulties in attempting this from above, but let’s continue assuming we have a system in place which can prescribe the distance somehow.&lt;/p&gt;
&lt;h2 id=&quot;existential-crisis&quot;&gt;Existential crisis&lt;/h2&gt;
&lt;p&gt;In explaining the logic to calculate the ancestor’s rounding, I simplified the approach dramatically. In reality there’s dozens of considerations that we’d need to account for. One of the largest problems returns back to rounding determined by an element’s existence.&lt;/p&gt;
&lt;p&gt;Imagine we have a card layout and all cards are marked to include rounding but no cards include any elements which initiate rounding; our “rounding focus” elements. This would mean that none of the cards have rounded corners. When we add our rounded button to one of the cards, rounding would exist &lt;em&gt;only on that card&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/rounding-bottom-up.png&quot; alt=&quot;Button with rounding only influences one sibling, others are not rounded.&quot;/&gt;&lt;/p&gt;
&lt;p&gt;If you’re thinking we could include a “virtual” rounding focus, a hidden element which triggers rounding, how do we allow the ancestors to measure the distance between edges? It’s possible the cards’ internal structures are completely different between them, making the rounding varied as well. What would be more desirable is for all sibling cards have the same rounding, whether they have a rounding focus or not. Except we’ve already determined that nested rounding is only determined between an element and ancestor, not from siblings. Do we then have further markings for rounded siblings to share values? Which sibling rounding takes priority?&lt;/p&gt;
&lt;p&gt;We’re not done with problems. If we put the rounding focus element within the card, what distance should we measure? We &lt;em&gt;could&lt;/em&gt; take the shortest distance and apply to all corners. However, what happens if we position that button in the center of the card; does the card become a circle because the button is positioned so far from the edges? Ok, perhaps we can set limits on the rounding using &lt;code&gt;max()&lt;/code&gt;. But then if this hits the max, outer marked elements would get the same max radius thereby breaking the nesting effect.&lt;/p&gt;
&lt;h2 id=&quot;level-headed&quot;&gt;Level headed&lt;/h2&gt;
&lt;p&gt;At this point you might ask why we haven’t done what has been before; create levels of rounding. Since we don’t need to be semantic, maybe this becomes a viable option?&lt;/p&gt;
&lt;p&gt;Let’s say we start at the base level again with a rounded button, then we have a card component which gets the next level up. What happens when we include a rounded input with a rounded button inside? We would need to insert a rounding level in between. The loom of insertion is the biggest drawback using levels. How could we possibly account for all the layout nesting configurations which may be rounded to avoid levels being added or orphaned?&lt;/p&gt;
&lt;p&gt;At this point we’re really more in search of a &lt;em&gt;layout&lt;/em&gt; system than just a rounding system. Prescribing layouts &lt;em&gt;could&lt;/em&gt; warrant the possibility of informing how round parts should be due to restrictions set by components of the system. We could know exactly what elements exist and the amount of space between them. Creating a robust layout system is outside the scope of this exploration since that would attempt to define all possible layouts for any hypothetical experience; a monumental task.&lt;/p&gt;
&lt;p&gt;So for the moment, I don’t believe there’s any possibility of a semantic nested rounding system due to the natural dependencies on existing elements. We’re unfortunately stuck with a more meaningless system which can provide few nesting effects for curated components.&lt;/p&gt;
&lt;p&gt;But maybe that’s the point. Other properties are decided in an experience based on qualities like feedback, hierarchy, and relationship:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The color orange often indicates a warning.&lt;/li&gt;
&lt;li&gt;Large text can support a section outline heading.&lt;/li&gt;
&lt;li&gt;Less space between items means they are related.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/FonsMans/status/1620022363722240000&quot;&gt;If this isn’t branding&lt;/a&gt;, what information does corner rounding convey past being round? &lt;a href=&quot;https://en.wiktionary.org/wiki/goose_egg&quot;&gt;Goose egg&lt;/a&gt; 🥚.&lt;/p&gt;</content:encoded></item><item><title>Minefield Context Protocol</title><link>https://blog.damato.design/posts/minefield-context-protocol</link><guid isPermaLink="true">https://blog.damato.design/posts/minefield-context-protocol</guid><pubDate>Wed, 26 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;AI is everywhere in tech now. It is in the tools we use, the products we build, and the way we interact with users. It feels like if you aren’t with AI, you are behind. While there’s plenty of questionable AI use, one thing is for sure: AI is making waves. And it’s really hard to keep up with the latest.&lt;/p&gt;
&lt;p&gt;One of the concepts that are gaining lots of discussion is the “MCP” which stands for Model Context Protocol. Anytime I’d ask what an MCP is, I’d usually hear it described as an API. So then, why isn’t it just called an API? Because it’s not really an API. Sound confusing? You bet!&lt;/p&gt;
&lt;p&gt;Just like how I learned to code from actually building something. I decided if I was going to truly learn what this thing was, I’d have to build one. So I did and this is how that went.&lt;/p&gt;
&lt;p&gt;If this sounds familiar to you, &lt;a href=&quot;https://www.youtube.com/watch?v=b9Zk5yDaino&quot;&gt;I did speak about this on Wireframe on Monday&lt;/a&gt;. You can think of this as the accompanying blog post. If you prefer listening to what I went through to make this, go ahead and click the link.&lt;/p&gt;
&lt;h2 id=&quot;you-have-too-much-stuff&quot;&gt;You have too much stuff&lt;/h2&gt;
&lt;p&gt;Some of the feedback that I get from folks who follow my work is that I do too many things. It’s hard to keep track of my latest research findings or development projects. Even my wife who works in the same field and lives under the same roof has trouble keeping up with my work. On top of this, much of my work is very abstract and hypothetical. It makes it hard to fully apply my work into real world scenarios without understanding all of the research behind it. Not to mention all the other factors that could contribute to friction in the implementation.&lt;/p&gt;
&lt;p&gt;So what if there was one place to learn about my work conveyed in a approachable way? Some way that you could learn about my work within the context of your own work? That’s what I set out to build, my own MCP server that aggregates my work and research findings into a single place.&lt;/p&gt;
&lt;p&gt;To do this, I needed two major units of work. I needed an MCP server to connect with MCP clients and I needed the server to fetch data from my domains in a way helpful for these systems to comphrehend.&lt;/p&gt;
&lt;h2 id=&quot;end-domain-data&quot;&gt;End-domain data&lt;/h2&gt;
&lt;p&gt;First, I wanted each of my end-domains: my personal site, the blog, and my design system to expose their data in a structured way. It was important to me that I’d follow some acceptabled standards for exposing this data. My thought was that I wanted these sites to opt-in for AI discovery.&lt;/p&gt;
&lt;p&gt;The way I found to do this is with using a &lt;code&gt;llms.txt&lt;/code&gt; file which has &lt;a href=&quot;https://llmstxt.org/&quot;&gt;an emerging standard&lt;/a&gt;. This file is like a sitemap but for AI. The content is actually markdown. Here’s a sample:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;md&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text);font-weight:bold&quot;&gt;# Title&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:var(--astro-code-color-text)&quot;&gt;&amp;gt; Optional description goes here&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:var(--astro-code-color-text)&quot;&gt;Optional details go here&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:var(--astro-code-color-text);font-weight:bold&quot;&gt;## Section name&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:var(--astro-code-color-text)&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-link);text-decoration:underline&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword);text-decoration:underline&quot;&gt;Link title&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-link);text-decoration:underline&quot;&gt;](https://link_url)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;: Optional link details&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:var(--astro-code-color-text);font-weight:bold&quot;&gt;## Optional&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:var(--astro-code-color-text)&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-link);text-decoration:underline&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword);text-decoration:underline&quot;&gt;Link title&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-link);text-decoration:underline&quot;&gt;](https://link_url)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Importantly, the links found in the file that go to content should also be markdown files. That means my site needed to serve not just the HTML pages, but also the Markdown source files. This way, the MCP server could fetch the raw content and parse it for AI consumption.&lt;/p&gt;
&lt;p&gt;For my personal site and the blog, this was fairly straightfoward because they are both written in Markdown and rendering that as raw text is a few lines of code for a &lt;code&gt;[slug].md.js&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { getCollection } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;astro:content&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; getStaticPaths&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; entries&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; getCollection&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;posts&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; entries&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.map&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;((entry) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;            params&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { slug&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; entry&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.id }&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;            props&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { entry }&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; GET&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({ props }) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; Response&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;props&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;entry&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.body&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        status&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 200&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        headers&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;text/plain; charset=utf-8&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The real problem was Storybook. Since the source for the files there are written in &lt;code&gt;stories.tsx&lt;/code&gt; files, it’s not a simple 1:1 translation. Admittedly, I vibe-coded the solution to this and wound up with nearly 1000 lines of code. Luckily, my system is open-source so you can &lt;a href=&quot;https://github.com/damato-design/system/blob/main/scripts/generate-llms.js&quot;&gt;grab this&lt;/a&gt; and remix it how you like for your own purposes.&lt;/p&gt;
&lt;p&gt;The script does a few things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Finds all the &lt;code&gt;stories.tsx&lt;/code&gt; files in the &lt;code&gt;src/components&lt;/code&gt; directory.&lt;/li&gt;
&lt;li&gt;Parses the file to extract  JSDoc, component category and name, and stories.&lt;/li&gt;
&lt;li&gt;Determines the props from the imported component type definition.&lt;/li&gt;
&lt;li&gt;Renders component stories as JSX instead of the less useful Story source.&lt;/li&gt;
&lt;li&gt;Generates a Markdown file for each component and a &lt;code&gt;llms.txt&lt;/code&gt; file with all of the components.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With this in place, all of my end-domains are now exposing their data in a structured way for AI discovery and consumption.&lt;/p&gt;
&lt;h2 id=&quot;the-mcp-server&quot;&gt;The MCP server&lt;/h2&gt;
&lt;p&gt;My MCP server is a very simple Netlify project. It was heavily inspired by &lt;a href=&quot;https://developers.netlify.com/guides/write-mcps-on-netlify/&quot;&gt;this guide on Netlify&lt;/a&gt;. Much of the scaffolding is the same except registering tools and resources which is the main difference.&lt;/p&gt;
&lt;h3 id=&quot;resources--tools&quot;&gt;Resources &amp;amp; Tools&lt;/h3&gt;
&lt;p&gt;When I went into this project, I was under the impression that everything I was going to offer from this server would have been resources. Resources are basically static files that the server can provide. It’s like requesting a library book. You receive the book with no modifications to the content, just as it is.&lt;/p&gt;
&lt;p&gt;For resources there’s two actions that clients need to accept: list resources and get resource. List resources is telling the client what is available, and get resource is fetching the content of a resource. This maps 1:1 to what was created at the end-domains earlier. The &lt;code&gt;llms.txt&lt;/code&gt; is the list of resources, while each of the Markdown files is a get. The slightly annoying thing is that we need to transform the &lt;code&gt;llms.txt&lt;/code&gt; Markdown into structured data. While I made my own using the Markdown AST tools, there seems to be &lt;a href=&quot;https://www.npmjs.com/package/parse-llms-txt&quot;&gt;a newly created package&lt;/a&gt; that might help in the parsing. Though I take pause to it not having a link to the source to know what it is doing.&lt;/p&gt;
&lt;p&gt;Once you have it parsed, you can register each as a resource. For my MCP, I wanted the resources to have the following URI structure:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;subdomain://category/slug&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The MCP specification allow you to make up your own URI scheme and my sites generally follow this shallow pattern. This is a resource URI meant for the server to use internally to look up its resources. Then you can use &lt;a href=&quot;https://github.com/modelcontextprotocol/typescript-sdk&quot;&gt;the official MCP Typescript SDK&lt;/a&gt; to register the resource template assuming you have &lt;code&gt;LIST_RESOURCES_META&lt;/code&gt; to configure the resource and a function &lt;code&gt;listResources()&lt;/code&gt; to handle the fetching:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;server&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.registerResource&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;    &amp;#39;resources&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    new&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; ResourceTemplate&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;{subdomain}://{category}/{slug}&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { list&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; undefined&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; })&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    LIST_RESOURCES_META&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    listResources&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The thing that bothered me is that &lt;code&gt;{ list: undefined }&lt;/code&gt; setting. It was unclear what the purpose of that was, and after some vibe-coding sessions, Claude suggested I use the &lt;code&gt;server.setRequestHandler()&lt;/code&gt; method to define resources. So, if you’re building something similar, you might want that method over the helper methods found prominently in the &lt;code&gt;README.md&lt;/code&gt; for the SDK. Especially since my resources are dynamic; they don’t truly exist on the server.&lt;/p&gt;
&lt;p&gt;A gotcha here is that some MCP clients, systems that speak to MCP servers, don’t support reading resources. They need a tool to access the resources. So, that required that I include tools. Tools is fancy word for something that can process data. Generally we’d think of something like a POST request for an API. In this case, in order for some clients to access the resources, I needed to create a pathway for them to make the request. For my system, it was recommended to use the &lt;code&gt;server.setRequestHandler()&lt;/code&gt; again, but as per the &lt;code&gt;README.md&lt;/code&gt;, registering a tool is done like this, assuming you have a &lt;code&gt;GET_RESOURCE_META&lt;/code&gt; to configure the tool and a function &lt;code&gt;getResource()&lt;/code&gt; to perform the lookup:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;server&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.registerTool&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;    &amp;#39;get_resource&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    GET_RESOURCE_META&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    getResource&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;stdio-vs-https&quot;&gt;STDIO vs HTTPS&lt;/h2&gt;
&lt;p&gt;Another thing that was being thrown around as common knowledge was MCP servers and clients having better support for STDIO over HTTPS. Because I program primarily on the web, I didn’t know what STDIO was. I just thought it was some other way of making the same server. In reality, STDIO is a way of identifying a MCP server than is meant to be installed locally on a persons computer. The HTTPS MCP server is a more recent development, which explains why I found it really hard to develop and test. My way of testing was just pushing the server up and hitting it in Cursor to see if I could connect and have it respond. Definitely not scalable, and I hope there’s better tools out there that can help in this area. The Netlify article speaks about making a hybrid server, and there’s something called &lt;a href=&quot;https://github.com/modelcontextprotocol/mcpb&quot;&gt;MCP Bundles&lt;/a&gt; that could be cool to try. Though I prefer the HTTP version. I find hitting a URL much easier than downloading and installing something.&lt;/p&gt;
&lt;h2 id=&quot;what-now&quot;&gt;What now?&lt;/h2&gt;
&lt;p&gt;The server is located at &lt;a href=&quot;https://mcp.damato.design&quot;&gt;&lt;code&gt;mcp.damato.design&lt;/code&gt;&lt;/a&gt; and the homepage has instructions on how you can add it to your MCP client of choice. This helps show my aptitude with AI technologies, while providing access to my research in a contextual way. It was filled with areas of my own learning and seeing all of the gotchas and missing standards shows how much people are still trying to figure all of this out. It was effectively a weekend project, and something you might want to consider trying to keep your skills in the game. Happy vibing?&lt;/p&gt;</content:encoded></item><item><title>Mixinimation</title><link>https://blog.damato.design/posts/mixinimation</link><guid isPermaLink="true">https://blog.damato.design/posts/mixinimation</guid><pubDate>Thu, 30 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;Warning, you probably don’t want to what this post describes anywhere. It’s for funsies.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;In speaking with a colleague, we were discussing solutions for people who were unable to use a framework’s custom component that still expected to have the styles for that component. Think of how you might have a React &lt;code&gt;&amp;lt;Button/&amp;gt;&lt;/code&gt; that would need to be visually similar to some static HTML page &lt;code&gt;&amp;lt;button/&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Folks writing CSS normally should quickly identify that placing all of the necessary styles under a single identifiable selector that can be applied to the element is the normal way of getting the job done.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.my-button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;    /** Reusable styles for the button here */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;my-button&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;Click me&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This assumes that the styles for &lt;code&gt;.my-button&lt;/code&gt; are found on the same page as the HTML &lt;code&gt;&amp;lt;button class=&amp;quot;my-button&amp;quot;/&amp;gt;&lt;/code&gt;. This is a reasonable method for having reusable styles.&lt;/p&gt;
&lt;p&gt;But maybe you don’t have the ability to update the HTML, how would you change the CSS such that the buttons would receive the styles? What you should first land on is updating the selector to be more generic:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;    /** Reusable styles for the button here */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, it’s possible that we don’t want to affect &lt;em&gt;all&lt;/em&gt; buttons this way. Specifically, we want to have some reusable styles that are written for the common &lt;code&gt;&amp;lt;Button/&amp;gt;&lt;/code&gt; component, but we also want to take those same styles and create a new stylesheet specific for when we can’t access the HTML. In other words, we don’t want to write the same styles twice, but we do want to change what those styles target. How could we do this?&lt;/p&gt;
&lt;p&gt;If you’re familiar with the CSS tooling ecosystem, you might suggest using a &lt;a href=&quot;https://sass-lang.com/guide/#mixins&quot;&gt;&lt;code&gt;@mixin&lt;/code&gt; syntax made popular by Sass&lt;/a&gt;. That will allow the styles to be written once, and be reused underneath different selectors.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;scss&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;@mixin&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; my-button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;    /** Reusable styles for the button here */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-comment)&quot;&gt;/** In the &amp;lt;Button/&amp;gt; component styles */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.my-button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    @include&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; my-button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-comment)&quot;&gt;/** In the restricted HTML styles */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    @include&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; my-button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unfortunately, this is not native CSS syntax &lt;a href=&quot;https://github.com/w3c/csswg-drafts/issues/9350#issuecomment-1939628591&quot;&gt;yet&lt;/a&gt;. So, this assumes that you are using a preprocessor to transform the &lt;code&gt;@mixin&lt;/code&gt; syntax into native CSS that the browser can parse. Though, I was curious; is there a way we can get mixin behavior in CSS today? And I think there is…&lt;/p&gt;
&lt;h2 id=&quot;keyframes&quot;&gt;Keyframes&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;@keyframes&lt;/code&gt; syntax is a method to add a collection of styles to an element. Typically, we’d define blocks of declarations for each point in the keyframe timeline. We could define all of these styles as the &lt;code&gt;from&lt;/code&gt; and &lt;code&gt;to&lt;/code&gt; points, causing these styles to be applied for the entire duration of the animation.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-keyword)&quot;&gt;@keyframes&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; mixin-button {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    from, to { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;/** Reusable styles */&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we can write the animation value as the following:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.my-button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    animation&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; mixin-button 0.001&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;ms&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; forwards&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;animation&lt;/code&gt; shorthand has three values. The first is the &lt;code&gt;animation-name&lt;/code&gt; value which refers to the &lt;code&gt;@keyframes&lt;/code&gt; name set earlier. The next is the &lt;code&gt;animation-duration&lt;/code&gt; which cannot be &lt;code&gt;0&lt;/code&gt;, the default. Setting to a very small value causes the animation to be nearly immediate. The &lt;code&gt;animation-fill-mode&lt;/code&gt; is set to forwards to ensure that the styles provided by the animation continue past the end of the animation so they persist after the very short duration.&lt;/p&gt;
&lt;p&gt;Now remembering to write those three values in the shorthand can be a bit cumbersome, so instead we can hide all of this in a CSS custom property.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-keyword)&quot;&gt;@property&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; --mixin-button {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  syntax: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  inherits: false;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  initial-value&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;mixin-button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.001ms&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; forwards;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This allows us to use the following syntax to apply all of the styles using a single property-value pair under a selector.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-comment)&quot;&gt;/** In the &amp;lt;Button/&amp;gt; component styles */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.my-button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    animation&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--mixin-button)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-comment)&quot;&gt;/** In the restricted HTML styles */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    animation&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--mixin-button)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here’s the whole implementation working in Codepen:&lt;/p&gt;
&lt;iframe height=&quot;500&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;Mixinimation&quot; src=&quot;https://codepen.io/fauxserious/embed/YPKgwJj/ab3653ad281c25f70299076c52a2c7f5?default-tab=css%2Cresult&quot; frameborder=&quot;no&quot; loading=&quot;lazy&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/fauxserious/pen/YPKgwJj/ab3653ad281c25f70299076c52a2c7f5&quot;&gt;
Mixinimation&lt;/a&gt; by Donnie D’Amato (&lt;a href=&quot;https://codepen.io/fauxserious&quot;&gt;@fauxserious&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;&lt;em&gt;&amp;lt;Laughs maniacally into his computer&amp;gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;drawbacks&quot;&gt;Drawbacks&lt;/h2&gt;
&lt;p&gt;Ignoring the hacky nature of applying all the styles by hiding them underneath the &lt;code&gt;animation&lt;/code&gt; property, one drawback to this will also be where actual animations would be expected for these elements. While there is a syntax to apply multiple animations to a single element, I’m not sure how these might conflict. Additionally, if you are using a &lt;a href=&quot;https://davidwalsh.name/detect-node-insertion&quot;&gt;node detection script&lt;/a&gt;, the animation would fire for all of these elements if listening for animations.&lt;/p&gt;
&lt;p&gt;My recommendation: try it out, put it in the dark corner of your toolbox but, avoid reaching for this unless you really have challenging constraints. We’re all waiting patiently for more native solutions and with CSS moving fast, it’ll be here sooner than we realize.&lt;/p&gt;</content:encoded></item><item><title>My Top 4</title><link>https://blog.damato.design/posts/my-top-4</link><guid isPermaLink="true">https://blog.damato.design/posts/my-top-4</guid><pubDate>Fri, 15 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;For a &lt;a href=&quot;https://www.youtube.com/watch?v=kvf33puDRuw&quot;&gt;recent episode of wireframe&lt;/a&gt;, I borrowed some questions from another person’s AMA. Overall, good questions but one of them stuck out to me where I wanted to give it more thought:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You are asked to build a website but you can use only 4 CSS properties, what are those?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It’s clear to me that you’d have to think strategically about this. While I’d say that something like &lt;code&gt;display&lt;/code&gt; is super powerful, it also often requires additional properties to make things behave afterward. So, the key is to think of properties that stand on their own and can have some significant impact once used. Additionally, it’s pretty clear what we’re going to be working on is a Craiglist-like design since I can’t use a lot of properties for aesthetic purposes.&lt;/p&gt;
&lt;p&gt;Without further ado, here’s my picks:&lt;/p&gt;
&lt;h2 id=&quot;overflow-wrap&quot;&gt;&lt;code&gt;overflow-wrap&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;This might be a property you aren’t using but I truly believe it should be in &lt;a href=&quot;https://www.joshwcomeau.com/css/custom-css-reset/&quot;&gt;people’s resets&lt;/a&gt;. Specifically &lt;code&gt;overflow-wrap: break-word&lt;/code&gt;. This ensures that long text such as URLs don’t break out of their containers. While it’s possible you might not need it on your site today, you’ll probably want to have it for the future.&lt;/p&gt;
&lt;h2 id=&quot;max-width&quot;&gt;&lt;code&gt;max-width&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;The prime example I’m thinking of is &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; elements rendering as larger than their container. Setting &lt;code&gt;max-width: 100%&lt;/code&gt; on these, along with other similar elements will help ensure that they don’t break layouts. This would also be helpful to keep long lines of text from occuring for readability. Even if the content itself might not be centered nicely on the page without something like &lt;code&gt;margin-inline: auto&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;margin&quot;&gt;&lt;code&gt;margin&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Speaking of &lt;code&gt;margin&lt;/code&gt;, I’m adding it to my list. Between the ability to horizontally center content and some of the egregious values set in browser defaults, having this will really clean up the overall hierarchy and presentation of a page. The use of the shorthand values will help here so that I can get horizontal centering with &lt;code&gt;margin: 0 auto&lt;/code&gt; and fix defaults with &lt;code&gt;margin: 0 0 8px&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;scroll-behavior&quot;&gt;&lt;code&gt;scroll-behavior&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;The reason I’m adding this, specifically &lt;code&gt;scroll-behavior: smooth&lt;/code&gt;, is for &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/Hash_routing&quot;&gt;hash routing&lt;/a&gt; on links. For example, when I’m reading &lt;a href=&quot;https://drafts.csswg.org/&quot;&gt;working group specifications&lt;/a&gt; and click a link, it often jumps somewhere making it really hard to know if I was navigated to another page or where this next section is relative to the old section I was just looking at. Smoothly scrolling after clicking the link makes the relationship more clear. Importantly, this would need to be inside of a &lt;code&gt;@media (prefers-reduced-motion)&lt;/code&gt; rule to be ignored for folks who are sensitive to motion. So, it’s possible my fourth rule could be wasted because of this.&lt;/p&gt;
&lt;p&gt;I made a quick sample page to demonstrate the usage.&lt;/p&gt;
&lt;iframe height=&quot;500&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;Untitled&quot; src=&quot;https://codepen.io/fauxserious/embed/ByoJdLd?default-tab=css%2Cresult&quot; frameborder=&quot;no&quot; loading=&quot;lazy&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/fauxserious/pen/ByoJdLd&quot;&gt;
Untitled&lt;/a&gt; by Donnie D’Amato (&lt;a href=&quot;https://codepen.io/fauxserious&quot;&gt;@fauxserious&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;What are your top 4? 🤔&lt;/p&gt;</content:encoded></item><item><title>No more modals</title><link>https://blog.damato.design/posts/no-more-modals</link><guid isPermaLink="true">https://blog.damato.design/posts/no-more-modals</guid><pubDate>Sun, 05 Jun 2022 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;Have you ever landed on a web page and have it immediately ask you for a location? How about while you are reading an article and, after you scroll down to read more, you get an advertisement covering your next paragraph? These are super annoying patterns but why are they annoying?&lt;/p&gt;
&lt;h2 id=&quot;surprising-popups&quot;&gt;Surprising popups&lt;/h2&gt;
&lt;p&gt;When a user has a specific goal in mind and an interruption occurs, the user will find it annoying if that interruption does not relate to their current workflow. This can be expanded to any generic UX pattern; where expectations aren’t met and frustration increases. However, there is a special place for popups because they &lt;em&gt;interrupt&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;There is a fine line between the popup and the modal. &lt;strong&gt;The modal &lt;em&gt;must be related&lt;/em&gt; to the user’s current workflow&lt;/strong&gt;. This means that the user triggered this popup and it meets the user’s expectations.&lt;/p&gt;
&lt;h2 id=&quot;reasons-to-use-a-modal&quot;&gt;Reasons to use a modal&lt;/h2&gt;
&lt;p&gt;The designer could choose a modal to interrupt the user (as all popups do) and cause the user to slow down for some important information in order to proceed. A good example is the destructive confirmation modal which helps ensure that the delete button press was intended. The user is expected to do a bit more work here so important data isn’t erased. So, the designer requires one more hit target to be pressed before continuing. The modal here also shows that the user can return to the original state just behind the message and that nothing has changed yet.&lt;/p&gt;
&lt;p&gt;Along with this previous idea, another valid reason to provide a modal is to show the user that they are still within the current context. A good example here is adding an image to a blog post. It would be more helpful to show that the user’s content remains while completing a new task of selecting an asset from the gallery. If we were to provide a new page for this experience, the user would not be confident that their content was saved. Showing that their content is persistent behind the modal establishes trust that the user will return as they once left.&lt;/p&gt;
&lt;p&gt;So to recap, you may consider using a modal:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;if you believe the user must slow down before continuing the current task.&lt;/li&gt;
&lt;li&gt;if you believe the user does not trust that current changes will persist while they need to complete a different but related task.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;questionable-practices&quot;&gt;Questionable practices&lt;/h2&gt;
&lt;p&gt;I’ve seen dozens of workflows using a modal which could have been another pattern entirely:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If the user could return to the experience using a url; the experience should probably be a new page.&lt;/li&gt;
&lt;li&gt;If the user needs to create or edit an entity with many fields (eg.: a profile, a product); the experience should probably be a new page or incorporated into the current experience.&lt;/li&gt;
&lt;li&gt;If the user needs to edit a value; the experience should probably be incorporated into the current experience.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;An example that I’ve seen recently is a profile review experience. Once clicking your avatar in the application a &lt;em&gt;modal&lt;/em&gt; appears above your current workflow. From here you can edit fields and save to return. However, you may also change your avatar photo. After selecting a photo, you are presented &lt;em&gt;another modal&lt;/em&gt; allowing the user to resize the photo and save the changes, returning you to the previous modal. So how could this experience be redesigned?&lt;/p&gt;
&lt;p&gt;First, clicking on your profile should navigate the user to their profile. We expect this to be a url and therefore a new page. From here, the user is given several fields of values they can edit directly. Let’s continue with this pattern by allowing the user to edit their avatar here as well. Use a slider to resize and drag-and-drop to reposition the photo in the thumbnail. The profile would hold the original image and on save, it would provide an avatar sized adjustment of that original for use across the site. We’ve taken a multi-modal experience to a zero-modal one.&lt;/p&gt;
&lt;p&gt;Let’s be clear here, I’m not recommending to remove &lt;em&gt;all&lt;/em&gt; modals from experiences. As mentioned above, if the user was able to delete their profile, a modal confirming the action would be helpful for the reasons stated above. Although even this could be avoided by requiring the user type a word or phrase into a field before executing the destructive action. It shows deliberate intent over accidental button clicks.&lt;/p&gt;
&lt;p&gt;It’s common to find modals used to login or signup. Consider using a separate page unless you allow the user to make customizations before creating an account. In this case, you’ll consider using a modal to show unauthenticated progress is maintained while they complete the signup process. Make sure the signup process is reduced down to the essential fields. Allow the user to include additional information later in their profile.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.nngroup.com/&quot;&gt;NN/Group&lt;/a&gt; also provides a few additional recommendations for when to use modals. One of the examples is a wizard which breaks down a complicated workflow into steps. What’s important here is the second paragraph:&lt;/p&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://www.nngroup.com/articles/modal-nonmodal-dialog&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;However, it’s important to note that a modal with multiple steps will just prolong the amount of time spent away from the main tasks, making it more likely that users will forget what they were doing in the first place.&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://www.nngroup.com/articles/modal-nonmodal-dialog&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;https://www.nngroup.com/articles/modal-nonmodal-dialog&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;p&gt;In my opinion this describes that we &lt;em&gt;shouldn’t&lt;/em&gt; be using a modal for wizards and instead provide a navigational pattern linking to pages sequentially; allowing the user to return to steps easily. This is also relevant to their following comment about lessening a user’s effort. The point of designing an experience is to do just that. So, asking if the user is working with an agent could be a question exposed as a checkbox while filling out the form for a open house. That selection could be saved for subsequent open house requests. This simplifies the experience instead of disrupting the user with a question the system forgot to ask when it was more relevant.&lt;/p&gt;
&lt;p&gt;Speaking of the real estate industry, many web sites of this genre use a &lt;a href=&quot;https://mdbootstrap.com/docs/standard/components/lightbox/&quot;&gt;lightbox&lt;/a&gt; (ie. a carousel in a modal) due to the need for viewing a set of high quality images of a property. Without diving too deeply into &lt;a href=&quot;https://shouldiuseacarousel.com/&quot;&gt;the decision to use a carousel&lt;/a&gt;, the decision to use a modal is debateable. Full screen images could be provided as separate urls; making the photos easily sharable to other interested parties. Closing the experience could return the user back to the listing; just like a close button would. Browser navigation could also assist in wayfinding between photos and the original listing along with common carousel-like controls.&lt;/p&gt;
&lt;h2 id=&quot;accessibility&quot;&gt;Accessibility&lt;/h2&gt;
&lt;p&gt;Attempting to make a modal fully accessible is a serious challenge. For example, you’ll need to indicate that a new area of the page has been created, and focus must enter this area and be trapped for the duration of the experience until the task is complete. At which point, focus must return to the initial trigger of the modal. What actually receives focus (a child of the modal or the modal itself) is actually &lt;a href=&quot;https://www.scottohara.me/blog/2019/03/05/open-dialog.html&quot;&gt;up for debate&lt;/a&gt;; making a recommendation for it unclear. Additionally, events should not occur behind the modal which is easier said than done. Even with &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/inert&quot;&gt;the new &lt;code&gt;inert&lt;/code&gt; attribute&lt;/a&gt;, ensuring that other elements are still accessible could be tricky with the introduction of third-party resources that need events outside of the modal.&lt;/p&gt;
&lt;p&gt;As you might imagine, things become increasing difficult with &lt;a href=&quot;https://github.com/w3c/aria-practices/issues/1241&quot;&gt;more modals&lt;/a&gt; added to the experience. How to juggle focus? What the screen reader should announce? How to navigate between these popups?&lt;/p&gt;
&lt;p&gt;Even &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog&quot;&gt;the native &lt;code&gt;&amp;lt;dialog/&amp;gt;&lt;/code&gt; element&lt;/a&gt; &lt;a href=&quot;https://a11y-dialog.netlify.app/advanced/dialog-element/&quot;&gt;isn’t shipped fully accessible&lt;/a&gt;. At the moment, we can’t even trust the browsers to support accessibility like other elements do. There’s no avoiding some amount of custom behavior which is bound to have variations of approach and unintended feature gaps.&lt;/p&gt;
&lt;h2 id=&quot;as-a-design-constraint&quot;&gt;As a design constraint&lt;/h2&gt;
&lt;p&gt;The modal should not live at the top of the designer’s toolbox. Make it a design constraint instead. Explore possible workflows without the modal and see how far you can get. I have confidence that most experiences can avoid the modal pattern for something more useful.&lt;/p&gt;
&lt;p&gt;It’s important to truly design with emphathy when crafting an experience. Perhaps, we should provide a double confirmation pattern before choosing some design directions? Imagine that!&lt;/p&gt;</content:encoded></item><item><title>On being extra</title><link>https://blog.damato.design/posts/on-being-extra</link><guid isPermaLink="true">https://blog.damato.design/posts/on-being-extra</guid><pubDate>Wed, 29 May 2024 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;While &lt;a href=&quot;/posts/truly-semantic&quot;&gt;I don’t recommend scales within the semantic set&lt;/a&gt;, it could be helpful in your primitives. One way of providing a scale is through something called “T-shirt sizing”. In this method, each size is provided in a similar way to how you might find sizes of clothing in a store. You might choose this type of scale when you expect the middle value to be the default and have values exist in opposite directions. In other words, you’d start with &lt;code&gt;medium&lt;/code&gt; or &lt;code&gt;md&lt;/code&gt;, and then have a smaller value represented with &lt;code&gt;small&lt;/code&gt; or &lt;code&gt;sm&lt;/code&gt; and a larger value represented with &lt;code&gt;large&lt;/code&gt; or &lt;code&gt;lg&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The T-shirt sizing scale is most frequently found describing space. In fact, I mention it as a direction within &lt;a href=&quot;https://gridless.design/&quot;&gt;Gridless Design&lt;/a&gt;. While &lt;a href=&quot;https://complementary.space/&quot;&gt;I have discovered a more semantic method of applying space&lt;/a&gt; since then, the T-shirt sizing approach remains popular and is appropriate for primitive token sets most certainly.&lt;/p&gt;
&lt;p&gt;In seeing folks demonstrate their T-shirt sizing scale, one thing irks me. It’s about how people handle being “extra”.&lt;/p&gt;
&lt;h2 id=&quot;growing-badly&quot;&gt;Growing badly&lt;/h2&gt;
&lt;p&gt;Certainly, your scale will most likely exist to have more than 3 sizes, and when that occurs this extends into “extra” territory. In other words, you’ll begin to have values for &lt;code&gt;xs&lt;/code&gt; and &lt;code&gt;xl&lt;/code&gt; to go out from either direction of &lt;code&gt;small&lt;/code&gt; and &lt;code&gt;large&lt;/code&gt;. So far, so good. But if you extend one more step in either direction, you’ll begin to see and example like this: &lt;code&gt;xxs&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Certainly, the expectation is that this is “extra extra small” or “double X S”. The problem is more apparent as you include more sizes, you’ll get &lt;code&gt;xxxs&lt;/code&gt; and &lt;code&gt;xxxxs&lt;/code&gt;; the representation becomes longer with each size.&lt;/p&gt;
&lt;p&gt;The fix for this is very simple, use a number to indicate the number of X’s, so for &lt;code&gt;xxxxs&lt;/code&gt;, you’d replace with &lt;code&gt;4xs&lt;/code&gt;. In this way, you aren’t repeating the character which increase the length of the representation. It is also more clear how many X’s in the name instead of needing to count at larger amounts. Of course, this goes for the &lt;code&gt;xl&lt;/code&gt; direction too.&lt;/p&gt;
&lt;h2 id=&quot;considerations&quot;&gt;Considerations&lt;/h2&gt;
&lt;p&gt;So why &lt;em&gt;aren’t&lt;/em&gt; people doing this? I’m going to make some assumptions.&lt;/p&gt;
&lt;p&gt;Perhaps there is a constraint that the representation &lt;em&gt;must&lt;/em&gt; start with an alpha character. For example, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id&quot;&gt;HTML &lt;code&gt;id&lt;/code&gt; attributes should start with an alpha character&lt;/a&gt;, and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/Variables#an_aside_on_variable_naming_rules&quot;&gt;Javascript variables also cannot start with a number&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If this is the case, then you can do one of two things. You could flip the X and number which would create &lt;code&gt;x2l&lt;/code&gt;. This is most likely less clear what it is meant to convey but it does keep the number of characters low if that is beneficial in some way. The other option is to prefix with alpha characters like a namespace. &lt;code&gt;size-2xl&lt;/code&gt; is more readable but longer if that is critical. I’d imagine the latter is more appropriate, as this also indicates what set this representation is meant to be included within.&lt;/p&gt;
&lt;p&gt;Another possiblity is that the number suggests a relationship within the value. A person might perceive that &lt;code&gt;2xl&lt;/code&gt; is twice as large as &lt;code&gt;xl&lt;/code&gt; which may not be the case. The relationship is more ambiguous when numbers aren’t included. I’m not confident this is the perception, as we don’t commonly assume that &lt;code&gt;color-red-200&lt;/code&gt; is “twice as red” than &lt;code&gt;color-red-100&lt;/code&gt;. Though the mental model is wholly different in comparing color to size. Doubling color isn’t an exercise we normally consider, but doubling an amount of space would be.&lt;/p&gt;
&lt;p&gt;And finally, the good ol’ &lt;a href=&quot;https://en.wikipedia.org/wiki/Bandwagon_effect&quot;&gt;Bandwagon Effect&lt;/a&gt;. Some team copied another system that looked good enough and wound up with a scale that could have been improved but, due to lack of resources, was never corrected. The team is now stuck smashing that X key until the correct value is set.&lt;/p&gt;
&lt;p&gt;Is this nitpicky? Maybe. But I also think it’s an easy win to make a small part of the system more maintainable and easily referrable. If you’re considering T-shirt sizing in your system, then I highly recommend representing the extraness with numbers over excess Xs.&lt;/p&gt;
&lt;p&gt;XOXO 😊&lt;/p&gt;</content:encoded></item><item><title>Ondark virus</title><link>https://blog.damato.design/posts/ondark-virus</link><guid isPermaLink="true">https://blog.damato.design/posts/ondark-virus</guid><pubDate>Thu, 12 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;The “ondark” virus is infecting token names in the design systems community everywhere. I’ve tried providing recommendations in token related posts and replies before. However, it seems this approach is becoming more wide-spread so I want to give it one final try to describe the problem with this naming scheme and provide some help with prevention.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This isn’t about what a token name should include, it’s about what it shouldn’t.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;prognosis&quot;&gt;Prognosis&lt;/h2&gt;
&lt;p&gt;Imagine you have a UI which is primarily light colored. Perhaps a white background with nearly black text. There’s a section in this UI that you want to have a stark contrast with the rest of the page. In this section, you have some text lockup and a call-to-action button. The button has all the same properties that other buttons in the system have, except it’s located on this dark background.&lt;/p&gt;
&lt;p&gt;Most folks might have a button prepared specifically for this scenario. We might even provide a configuration for when this happens in code. Under the hood, that might reference different tokens which point to specific &lt;code&gt;ondark&lt;/code&gt; values sent to the page.&lt;/p&gt;
&lt;iframe height=&quot;500&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;ondark&quot; src=&quot;https://codepen.io/fauxserious/embed/gOjWGaz?default-tab=html%2Cresult&amp;editable=true&quot; frameborder=&quot;no&quot; loading=&quot;lazy&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/fauxserious/pen/gOjWGaz&quot;&gt;
ondark&lt;/a&gt; by Donnie D’Amato (&lt;a href=&quot;https://codepen.io/fauxserious&quot;&gt;@fauxserious&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;This works fine for this section which covers just the background, text, and button.&lt;/p&gt;
&lt;p&gt;Soon after, a request comes in to show a comparison table in this area; showcasing the benefits of the product of feature. In the current system, you’d need tokens to describe all of the borders of the table. Maybe you have something generic that targets borders in this area. But unfortunately, you might see a problem begin to appear.&lt;/p&gt;
&lt;p&gt;The problem is that for every UI element that &lt;em&gt;might&lt;/em&gt; appear in this section in the future, you’d need to define an entirely new set of tokens to describe the color for that UI. This is especially exhausting since you’ve already defined tokens semantically for all of these things in the “default” environment. To fully cover the dark area, you’d need to &lt;strong&gt;double the amount of token names&lt;/strong&gt; to include the additional “ondark” (or “inverse”, “reverse”, “contrast”) infix.&lt;/p&gt;
&lt;p&gt;No bueno.&lt;/p&gt;
&lt;h2 id=&quot;remedy&quot;&gt;Remedy&lt;/h2&gt;
&lt;h3 id=&quot;semantic-tokens&quot;&gt;Semantic tokens&lt;/h3&gt;
&lt;p&gt;The first step is fully investing in semantic tokens. &lt;a href=&quot;/posts/tokens-as-intents&quot;&gt;I’ve called them “intents”&lt;/a&gt; in the past to further enforce the expectation that the name describes purpose over value. We’re talking about token names like &lt;code&gt;--button-background&lt;/code&gt; or &lt;code&gt;--input-focused-critical-border-color&lt;/code&gt; which give information about the component or pattern and the property being influenced. In no way does it give any information about what the value of this color is. The more you avoid encoding the value in the name, the more flexible your system will be with the opportunity for that color to change in the future.&lt;/p&gt;
&lt;p&gt;This extends to any token; describe the purpose and avoid the value when naming.&lt;/p&gt;
&lt;h3 id=&quot;scoped-themes&quot;&gt;Scoped themes&lt;/h3&gt;
&lt;p&gt;A theme is the collection of values assigned to semantic tokens. The semantic tokens are a contract that should have permanence and meet expectations of folks building UI over time. These are the tokens that appear on the &lt;em&gt;left-side&lt;/em&gt; of a theme. The values that would appear on the &lt;em&gt;right-side&lt;/em&gt; can and should have a separate stakeholder, most likely one that represents a brand. I recommend avoiding managing both sides if possible to not introduce subjective bias or confusion in token naming.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/token-responsibility.png&quot; alt=&quot;Be responsible for the left side theme assignment, avoid the right side&quot;/&gt;&lt;/p&gt;
&lt;p&gt;I cannot stress enough, &lt;strong&gt;how values are assigned on the right-side does not matter&lt;/strong&gt;. Values can be referenced, hard-coded, computed, or otherwise because they should never be used directly within the UI. A color palette is influenced by the brand and determines what &lt;code&gt;--brand-blue-500&lt;/code&gt; means. Here, the brand is responsible for curating the right-side values and how they are finally assigned to the left-side.&lt;/p&gt;
&lt;p&gt;The design system team is responsible for maintaining consistency on the left-side; that’s it. They should only focus on the semantic token names for those values to be assigned and how they might support describing the experience at scale.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;While I advocate for design systems folks to be hands-off for the right-side of the theme, it is not possible to be completely ignorant of what happens there. We should be providing guidance on best practices when curating the other side, especially in terms of accessibility. We should provide feedback when people attempt to choose color combinations that have low contrast or font-sizes that are illegible.&lt;/p&gt;&lt;p&gt;And certainly when posed with limited resources, it’s entirely possible for the design system team to manage both sides. But if you can avoid it, it’s one less thing to be responsible for.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;Note that for simplicity the idea of “dark-mode” is also well represented by providing a dark theme. A user preference for “high-contrast mode” is asking for a high-contrast theme. The mode is the user preference. The theme is a collection of value assignments that aim to satisfy the mode.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;Now for the key insight — instead of the dark area and the light colored page needing to be informed by a single theme, &lt;strong&gt;think of the dark area as an entirely separate theme&lt;/strong&gt;. In this way, the values that represent &lt;code&gt;--button-background&lt;/code&gt; can change depending on scope.&lt;/p&gt;
&lt;iframe height=&quot;500&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;ondark&quot; src=&quot;https://codepen.io/fauxserious/embed/jOpmGbR?default-tab=html%2Cresult&amp;editable=true&quot; frameborder=&quot;no&quot; loading=&quot;lazy&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/fauxserious/pen/jOpmGbR&quot;&gt;
ondark&lt;/a&gt; by Donnie D’Amato (&lt;a href=&quot;https://codepen.io/fauxserious&quot;&gt;@fauxserious&lt;/a&gt;)
on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;&lt;/iframe&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No additional configuration at the component level.&lt;/strong&gt; You don’t need to remember or even know that this button is on a “dark” surface.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No additional token names.&lt;/strong&gt; Self explanatory, naming is hard and scaling those names is even harder.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now the only name you need is the one describing the theme; “dark”.&lt;/p&gt;
&lt;h2 id=&quot;prescription&quot;&gt;Prescription&lt;/h2&gt;
&lt;p&gt;This still requires the design token values to be curated to account for a dark UI. If you worried about defining an entire new theme worth of tokens, start small. Only define the ones you need at first; maybe background, text and button. At some point you might have the resources to define it all and then you’ll have an entire new theme to try.&lt;/p&gt;
&lt;p&gt;I’ve considered going farther, specifically with surfaces that expect to demonstrate feedback (eg., warning banner). You might imagine this banner similar to the dark section above with a text lockup and action to take. I say if you have the resources to prepare this as a theme, go for it! You’ll be better prepared for when code samples might appear within the notification. Otherwise, you’ll need to be highly restrictive to the kinds of content that appear within various colored surfaces. And we all know how much designers love restrictions. 😉&lt;/p&gt;
&lt;p&gt;It’s possible to over compensate. As an example I wouldn’t recommend creating a separate theme for inline feedback elements. Badges, notification dots, and error text can and should also be handled semantically inside a normal theme. Just think of a newsletter signup in a dark section; it should have an error message if the input isn’t valid. If you think in surfaces, like a sub-artboard, then you’ll better identify when a scoped theme would help.&lt;/p&gt;
&lt;p&gt;This new recommendation also requires that the system delivering themes be flexible enough to request more than one. I think there’s an opportunity for some optimization here as well; where we statically analyze the page for tokens used within scopes and only serve what’s needed. However, to start you could just import the theme when a scope is added. The benefit of this is if the scoped theme hasn’t been included or the scope hasn’t been applied, it’ll fallback to the base theme values instead.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;This button has a black background&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; data-theme&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;dark&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;        &amp;lt;!-- Missing definition for the dark theme, &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;        everything here inherits from the light theme --&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;This button has a black background&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;recovery&quot;&gt;Recovery&lt;/h2&gt;
&lt;p&gt;If you’re already using the “ondark” naming convention, it’ll be hard to move to this new system. That goes for any semantic token that was expected for public use. Deprecating tokens at the semantic tier is very difficult because they could be used anywhere across the platform.&lt;/p&gt;
&lt;p&gt;Luckily there’s a path forward:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;First, you can setup the scopes and apply within the UI in the appropriate locations, making note of the UI elements that exist in those locations.&lt;/li&gt;
&lt;li&gt;Then define the values for those themes, perhaps reading from the “ondark” values.&lt;/li&gt;
&lt;li&gt;Start serving those themes to the pages, which will be inert at first because no UI elements should reference the tokens.&lt;/li&gt;
&lt;li&gt;Finally, either remove the component configuration that applies the dark theme or remove the “ondark” token assignments for the more generic tokens.&lt;/li&gt;
&lt;li&gt;You can now safely remove the “ondark” token virus from your system.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I wish you best of luck in your path toward recovery.&lt;/p&gt;
&lt;hr/&gt;
&lt;p&gt;&lt;strong&gt;EDIT (2023-01-12):&lt;/strong&gt; &lt;a href=&quot;https://desandro.com/&quot;&gt;Dave&lt;/a&gt; posted a great question as a follow-up and it deserves addressing.&lt;/p&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://twitter.com/desandro/status/1613568348331155456&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;I’m curious how you would accommodate session-level Dark Mode? Does the hero theme stay dark, or maybe sub-themes like &lt;code&gt;data-theme=&amp;#39;inverted&amp;#39;&lt;/code&gt;&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://twitter.com/desandro/status/1613568348331155456&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;Dave DeSandro&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/donniedamato/status/1613583101493481487&quot;&gt;My reply&lt;/a&gt; was half-joking but in seriousness, the answer is to continue leaning into semantic naming at the &lt;em&gt;scope&lt;/em&gt; level. For the purposes of this demonstration, it was more helpful to use the word “dark” to further cement what was happening within the scope. In practice, the scope should be described with some meaning or purpose for the change in scope over expected appearance. For the examples above, the “light” theme could instead be the “base” theme as it is meant to be the default. The “dark” theme could be “feature” theme as it is meant to highlight features (in our examples).&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; data-theme&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;base&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;Login&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; data-theme&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;feature&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;Click here&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This way user preferences could be read to determine what values are applied to which scope.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-comment)&quot;&gt;/* no-preference */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;data-theme&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;base&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;  /* light colored assignments */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-color-text)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;data-theme&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;feature&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;  /* dark colored assignments */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;@media&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (prefers-color-scheme&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; light) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;data-theme&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;base&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;    /* light colored assignments */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-color-text)&quot;&gt;  [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;data-theme&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;feature&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;    /* slight contrast to light assignments as needed */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;@media&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (prefers-color-scheme&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; dark) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;data-theme&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;base&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;    /* dark colored assignments */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-color-text)&quot;&gt;  [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;data-theme&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;feature&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;    /* slight contrast to dark assignments as needed */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you want to be more efficient, only serve the user-preference when it is set.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-comment)&quot;&gt;&amp;lt;!-- first stylesheet is no-preference --&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;link&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; href&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;default.css&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; rel&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;stylesheet&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;link&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; href&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;light.css&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; rel&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;stylesheet&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; media&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;(prefers-color-scheme: light)&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;link&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; href&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;dark.css&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; rel&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;stylesheet&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; media&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;(prefers-color-scheme: dark)&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, things get complicated when you are including user preference alongside the scoped themes but “ondark” is definitely not solving this. For scoped themes, it’s complex but not impossible. During the first pass, I recommend leaving user preference out to keep the execution simple but plan for it in a future implementation.&lt;/p&gt;
&lt;p&gt;If it was only as easy as &lt;code&gt;body { filter: invert(1); }&lt;/code&gt;!&lt;/p&gt;</content:encoded></item><item><title>Out of order</title><link>https://blog.damato.design/posts/out-of-order</link><guid isPermaLink="true">https://blog.damato.design/posts/out-of-order</guid><pubDate>Wed, 16 Apr 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;As someone who like to think he deeply understands the CSS I’m writing, I do everything I can to avoid using CSS that can cause unintended side effects. As an example, for my new &lt;a href=&quot;https://donnie.damato.design&quot;&gt;personal website&lt;/a&gt;, I use &lt;code&gt;z-index&lt;/code&gt; &lt;em&gt;once&lt;/em&gt; to handle the page tearing animation. Trying to manipulate the order of things using CSS can seem reasonable at first but often has hidden problems that you might not notice. I’d like to outline some of those problems here.&lt;/p&gt;
&lt;h2 id=&quot;whos-on-first&quot;&gt;Who’s on first?&lt;/h2&gt;
&lt;p&gt;Let’s say we have a dropdown component which produces some sort of flyout experience. We believe that setting some high &lt;code&gt;z-index&lt;/code&gt; value will ensure that it is always on top of the content:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.dropdown&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    z-index&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, when we create the modal component, we set it as a higher &lt;code&gt;z-index&lt;/code&gt; because it is meant to be disruptive and on top of everything:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.modal&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    z-index&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 200&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The question here is, what happens when the dropdown component is meant to be part of the modal composition? For example, perhaps you need to select from a large list of options within the modal. In the current setup, the flyout could appear &lt;em&gt;underneath&lt;/em&gt; the modal because the &lt;code&gt;z-index&lt;/code&gt; value for the dropdown is lower than the modal.&lt;/p&gt;
&lt;p&gt;Now, when many folks find this problem, they start adding exceptions. Ok when &lt;em&gt;this specific dropdown&lt;/em&gt; appears, we’re going to increase the &lt;code&gt;z-index&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.dropdown.but-only-this-one&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    z-index&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 300&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sure, this could work. But then when large teams are trying to use these components it turns into a priority war. With more things that are meant to appear on top of each other, it becomes less clear which items are more important at which times. Everyone thinks their use is the exception to the rule and then no system truly exists.&lt;/p&gt;
&lt;p&gt;Some design systems took &lt;a href=&quot;https://m2.material.io/design/environment/elevation.html#default-elevations&quot;&gt;Material’s guidelines for elevation&lt;/a&gt; and turned them into design tokens for &lt;code&gt;z-index&lt;/code&gt;. Unfortunately, based on my example above, this doesn’t work. It’s possible that your tooltip is meant to appear in a modal, causing its &lt;code&gt;z-index&lt;/code&gt; number to increase.&lt;/p&gt;
&lt;p&gt;So what’s the solution? Avoid using &lt;code&gt;z-index&lt;/code&gt; altogether.&lt;/p&gt;
&lt;p&gt;When you start working with the &lt;code&gt;position&lt;/code&gt; property, and then try reordering the elements, you should notice a certain quality. Having nothing else set, the order that the elements appear matches the DOM order. In other words, later elements will appear on top of elements that come before. In the following example, try rearranging the HTML elements without touching the CSS.&lt;/p&gt;
&lt;iframe height=&quot;500&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;Positioning&quot; src=&quot;https://codepen.io/fauxserious/embed/vEEYJoe?default-tab=html%2Cresult&quot; frameborder=&quot;no&quot; loading=&quot;lazy&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/fauxserious/pen/vEEYJoe&quot;&gt;
Positioning&lt;/a&gt; by Donnie D’Amato (&lt;a href=&quot;https://codepen.io/fauxserious&quot;&gt;@fauxserious&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;Notice that whatever box is rendered last, is the box that appears on top of the others. This means if we want things to appear on top of other things, we should be rendering them last in the DOM order.&lt;/p&gt;
&lt;p&gt;In fact, this is exactly how the new &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/Top_layer&quot;&gt;top-layer&lt;/a&gt; works in the DOM. The top-layer is exactly what it sounds like, it is a layer that exists on top of everything else in the page. That means even trying to set &lt;code&gt;z-index: Infinity&lt;/code&gt; will not work here. Speaking of &lt;code&gt;z-index&lt;/code&gt;, that doesn’t work on elements in this layer either. The only way to affect the order of elements here is by DOM order. The last rendered element in the layer is the element that appears on top. If you want something to be on top of that, you’ll need to append it to the layer.&lt;/p&gt;
&lt;h2 id=&quot;inset-fill&quot;&gt;Inset fill&lt;/h2&gt;
&lt;p&gt;But, let’s say you don’t need to do any flyouts or disruptions (good!). You want to do something more simple like have an element fill a container without itself contributing to the size of the container. Traditionally, we’d use the inset fill technique to do this.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.parent&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    position&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; relative&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-function)&quot;&gt;.child&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    position&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; absolute&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    inset&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;/* same as setting top, left, bottom, right all to 0 */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This was very common when we needed maintain the aspect ratio for media by using the &lt;a href=&quot;https://css-tricks.com/aspect-ratio-boxes/&quot;&gt;padding hack&lt;/a&gt;. While we don’t need that specific hack any longer, there’s still use-cases for making an element fill a parent container. In those cases, I still recommend avoiding the use of &lt;code&gt;z-index&lt;/code&gt; by making the element to appear on top last in the DOM order. But I’d also recommend avoiding the &lt;code&gt;position&lt;/code&gt; property altogether.&lt;/p&gt;
&lt;p&gt;Josh Comeau has &lt;a href=&quot;https://www.joshwcomeau.com/css/stacking-contexts/&quot;&gt;a great post about stacking contexts&lt;/a&gt; that you should absolutely read. But the tl;dr is that using &lt;code&gt;position&lt;/code&gt; creates a stacking context. This is good for when you want to use &lt;code&gt;z-index&lt;/code&gt; but bad when other stacking contexts are created elsewhere and conflict in some way. Most people don’t know &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_positioned_layout/Stacking_context#features_creating_stacking_contexts&quot;&gt;the properties that create stacking contexts&lt;/a&gt;, but these are usually the culprits to when you think you need to start introducing &lt;code&gt;z-index&lt;/code&gt; into your CSS. Here’s a few important points:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you create a container (for container queries) with &lt;code&gt;inline-size&lt;/code&gt; or &lt;code&gt;size&lt;/code&gt;, that creates a new stacking context.&lt;/li&gt;
&lt;li&gt;If you set &lt;code&gt;opacity&lt;/code&gt; on something to anything less than 1, that creates a new stacking context.&lt;/li&gt;
&lt;li&gt;Nearly anything related to transforms, filters, masks, and blend modes will create a new stacking context.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This illustrates one of the things that makes people upset about CSS. There are properties that can affect other things in the composition in ways you don’t expect. You’d think that simply setting &lt;code&gt;opacity: .5;&lt;/code&gt; is just making the element translucent, but there’s other side effects associated with it that could be unintended. Unfortunately, the only way to really know these is with experience. The more you avoid learning this, the more you’ll wonder what is happening every moment you begrudgingly write CSS.&lt;/p&gt;
&lt;p&gt;Getting back to the inset fill technique. Instead of using &lt;code&gt;position&lt;/code&gt;, I recommend trying to use &lt;code&gt;display: grid;&lt;/code&gt; instead:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.parent&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    display&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; grid&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;/** or inline-grid */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-function)&quot;&gt;.child&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    grid-area&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1 / 1 / -1 / -1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;grid-area&lt;/code&gt; set in the child says to make sure this item touches all of the edges of the parent grid, filling the space. This forces the element to appear on top of any other children that may be within the grid.&lt;/p&gt;
&lt;h2 id=&quot;reading-flow&quot;&gt;Reading flow&lt;/h2&gt;
&lt;p&gt;Ordering things in the third dimension isn’t the only way we can affect elements using CSS. We’ve had the &lt;code&gt;order&lt;/code&gt; property since the introduction of Flexbox. This has the ability to visually rearrange the elements in a composition without changing their order in the DOM.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.flex-child&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    order&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There’s other properties that can change the visual order, such as &lt;code&gt;flex-direction&lt;/code&gt; and even &lt;code&gt;grid-areas&lt;/code&gt;. However, my recommendation is to avoid doing this, and if you must change the order to update the DOM order instead.&lt;/p&gt;
&lt;p&gt;Now I know what you’re probably thinking, using JavaScript to rearrange the DOM sounds expensive when CSS would be much more performant and that’s true. The problem comes down to accessibility. The page structure should match the visual order of elements. If it doesn’t, then folks who can’t see the visual rearrangement can be confused about the order of the elements.&lt;/p&gt;
&lt;p&gt;Imagine that someone who uses an assistive technology has called a help line for assistance with their account. The person on the phone says, “click the first button”. If the DOM order doesn’t match the visual order, the first button could be different to these folks and cause confusion down the line.&lt;/p&gt;
&lt;p&gt;I keep this in mind when designing, and consider the ways I could keep the order maintained when the layout needs to change based on the available size. Sometimes though, you get a design in your inbox that can’t have reordering avoided. That’s when as of right now I’d recommend using a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver/ResizeObserver&quot;&gt;&lt;code&gt;ResizeObserver&lt;/code&gt;&lt;/a&gt; to reflow the elements instead of CSS for the reasons I’ve described above. &lt;a href=&quot;https://github.com/damato-design/system/blob/main/src/components/Box/reflow.ts&quot;&gt;Here’s an implementation&lt;/a&gt; for my design system playground.&lt;/p&gt;
&lt;h2 id=&quot;bring-order&quot;&gt;Bring order&lt;/h2&gt;
&lt;p&gt;Good things are on the way! There’s a new CSS property being discussed called &lt;code&gt;reading-flow&lt;/code&gt; which is designed to help the element order problems I’ve described above. If this property becomes available, then we could tell the browser what order the elements should be in if the visual order doesn’t match. Rachel Andrew has &lt;a href=&quot;https://chrome.dev/reading-flow-examples/&quot;&gt;some examples&lt;/a&gt; and &lt;a href=&quot;https://www.youtube.com/watch?v=X6azWrtHS-k&quot;&gt;a presentation&lt;/a&gt; on this. This is relating directly to the &lt;a href=&quot;https://github.com/w3c/csswg-drafts/issues/11243&quot;&gt;Masonry discussions&lt;/a&gt; to help understand what the intended flow is meant to be for the user. Having this along with top-layer will make setting the order of elements more clear than ever before.&lt;/p&gt;
&lt;p&gt;Bottom line is that when you are trying to update the order of elements using CSS, pause to think of the side-effects of these decisions and refer to some of the recommendations here to help keep a consistent structure.&lt;/p&gt;</content:encoded></item><item><title>People&apos;s Primitives</title><link>https://blog.damato.design/posts/peoples-primitives</link><guid isPermaLink="true">https://blog.damato.design/posts/peoples-primitives</guid><pubDate>Tue, 03 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;I tend to take a minimalist approach when it comes to design systems. One of the reasons for this is the empathy I have for maintainers of these systems. The responsibility of supporting a group of creatives while not being overwhelmed by the number of resources they need is a challenge. However, this doesn’t mean I don’t have empathy for the people looking to express themselves. It’s why I am so proud of the &lt;a href=&quot;https://mode.place&quot;&gt;Mise en Mode&lt;/a&gt; approach; that it allows for &lt;em&gt;infinite expressions&lt;/em&gt; in ways other systems would fail when pressed, and fail in different ways.&lt;/p&gt;
&lt;p&gt;One major drawback to Mise en Mode is being &lt;em&gt;new&lt;/em&gt;. Not just new in terms of being recent, but also in terms of thinking. It’s the same sort of paradigm shift that took responsive design years to change the way of working, and even more related to the need for semantic tokens to support both light and dark expressions. It’s just hard to think differently for many.&lt;/p&gt;
&lt;p&gt;So when I say, you—&lt;em&gt;collectively&lt;/em&gt;—need primitives but you—&lt;em&gt;yourself&lt;/em&gt;—don’t need primitives, it’s just a different way of thinking.&lt;/p&gt;
&lt;h2 id=&quot;why-you-collectively-need-primitives&quot;&gt;Why you collectively need primitives&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://tokenpedia.ds.house/terms/primitive/&quot;&gt;The definition of a primitive&lt;/a&gt; is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A tier of token meant to have a &lt;strong&gt;permanent value assigned&lt;/strong&gt;…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;An example of this might be &lt;code&gt;color-red-500&lt;/code&gt; which a person should reasonably expect the color red to be represented as a value, perhaps in the middle of a set of reds. A clear benefit to primitive tokens is their ease of reference. In other words, it is much easier to say and remember “color red five hundred” than it is to reference the related color channels that represent this specific color of red. This is helpful to communicate the idea across people and teams. &lt;em&gt;People need primitives.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;the-life-of-a-token&quot;&gt;The life of a token&lt;/h3&gt;
&lt;p&gt;Here’s a question that could split the room, when thinking about switching between light and dark expressions, &lt;strong&gt;should the value of &lt;code&gt;color-red-200&lt;/code&gt; change between these expressions?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In other words, do you expect something loosely like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;data-theme&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;light&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --color-red-200&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; color-mix&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(in oklch&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; red&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; white 20&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-color-text)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;data-theme&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;dark&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --color-red-200&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; color-mix&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(in oklch&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; red&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; black 20&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the example above, the light theme has the &lt;code&gt;200&lt;/code&gt; value represent a lighter red. While the dark theme has the same &lt;code&gt;200&lt;/code&gt; value represent a darker red.&lt;/p&gt;
&lt;p&gt;If you expect the value of &lt;code&gt;color-red-200&lt;/code&gt; to change in this way, this is fundamentally &lt;em&gt;not&lt;/em&gt; a primitive by definition. Primitive tokens are meant to represent permanent values. They are meant to act like constants in the system, just like how you might store an API key and then use it later. The key’s value is too hard to recall, so storing it in something human readable is helpful.&lt;/p&gt;
&lt;p&gt;Why we expect them to be permanent is to meet user expectations. Otherwise, the mental model of token &lt;code&gt;color-red-200&lt;/code&gt; needs to switch between the expression of light and dark. In one context &lt;code&gt;200&lt;/code&gt; would need to mean lighter, and in another &lt;code&gt;200&lt;/code&gt; would need to mean darker. It’s easy to get these confused when trying to select which one from the set you are supposed to use. Is &lt;code&gt;color-red-700&lt;/code&gt; the light one now, or is it &lt;code&gt;color-red-200&lt;/code&gt;? This is the job for semantic tokens which don’t need to know if the value is light or dark. Semantic tokens don’t describe values, they describe &lt;em&gt;intention&lt;/em&gt; and how we express those intentions can change. We can choose a different red from the set of reds. But we shouldn’t change what &lt;code&gt;color-red-200&lt;/code&gt; means. The agreement of how the primitives are prepared should be stable and meet expectations for the organization.&lt;/p&gt;
&lt;p&gt;This is especially the case when a brand changes from blue to red, as was the case for AirBnB. Assigning &lt;code&gt;color-blue-500&lt;/code&gt; to the logo might have seemed reasonable at the time. But once the new expression was introduced, it certainly doesn’t make sense to now change the assignment to a red shade for &lt;code&gt;color-blue-500&lt;/code&gt;. This would break expectations for the people using the system. A semantic token meant to describe where the brand color is shown would be more appropriate, and we can later reassign the value of that from blue to red or any other special expression in the future.&lt;/p&gt;
&lt;h2 id=&quot;why-you-yourself-dont-need-primitives&quot;&gt;Why you yourself don’t need primitives&lt;/h2&gt;
&lt;p&gt;At the point I hope I’ve illustrated the reason why tokens like &lt;code&gt;color-red-500&lt;/code&gt; are meant to be permanent and why they can be helpful to us. But the system itself doesn’t need them, especially a &lt;a href=&quot;/posts/truly-semantic/&quot;&gt;truly semantic&lt;/a&gt; one.&lt;/p&gt;
&lt;p&gt;Let’s compare the following two blocks of CSS:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;:root&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --error-text&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; #9e2000&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;:root&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --error-text&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--color-red-700)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Other than one having a more human readable value, &lt;strong&gt;what is the difference between these approaches?&lt;/strong&gt; Because the primitive is meant to be permanent, and the hard coded value &lt;em&gt;is&lt;/em&gt; permanent, there isn’t much difference. You could argue that if we’re going to reuse the &lt;code&gt;--color-red-700&lt;/code&gt; in multiple places, then having a variable is helpful. But think about the &lt;em&gt;act&lt;/em&gt; of reusing the variable. How would you reuse it? In a very basic sense, you would copy and paste the primitive in the places that it is meant to be reused. Well, you’d also do the same if you use the hexcode directly. You’d copy and paste it in the places it was meant to be reused.&lt;/p&gt;
&lt;p&gt;“But that’s not how I assign these values,” you say. “I don’t select from a list of hexcodes, I select from a list of names.” Precisely! You use your meaty eyes to look for the name in a dropdown somewhere, but there’s nothing keeping that dropdown from being the set of values themselves other than those meaty eyes of yours. This could be a dropdown of binary numbers for color. The result would be the same, but because you can’t read the value, you are uneasy about using the value. It just feels better when it’s readable.&lt;/p&gt;
&lt;p&gt;In fact, in a truly semantic system, the amount of times you’d be choosing a primitive should also be very small, maybe even once! This starts going into how to think of semantic naming and further using contextual expressions; a tangent to the current topic. But a good way to tell if some system could be more semantic is the number of times you use a single primitive. If you find yourself using it several times in a system, it’s possible that these assignments could be reduced to a more generic semantic token for them all. As always, my goal is having a small set of overall tokens, and removing the primitive tier completely is certainly less maintenance overall.&lt;/p&gt;
&lt;p&gt;You might think this is only viable when you are maintaining a single theme. However, I’ll argue this really hits home when you are supporting multiple themes. When supporting multiple themes, you could have v1, v2, and v3 of these themes. You could have themes for different seasons, different promotions, and different reasons. So instead of revisiting the same file over and over again, you make a new theme as a new file. A new collection of assignments to semantic tokens. The semantic tokens stay the same, but the assignments change.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;That’s what really changes.&lt;/em&gt; It’s not the tokens that change, it’s how you assign them. Semantic tokens are a proxy to the experience, but primitives should never be found there. Primitives should only exist in the exercise of assigning values, if at all! It is there in the act of curating that you might as well just use the raw code since you might never return to this theme. You might just create a whole new one from scratch for the next product need, with wholly new values to create that new expression.&lt;/p&gt;
&lt;h2 id=&quot;for-humans-and-human-like-systems&quot;&gt;For humans and human-like systems&lt;/h2&gt;
&lt;p&gt;The reality is that you most likely aren’t going to get rid of your primitive tier, especially in large organizations with lots of ideas being shared. People need to discuss design decisions and agreements between other humans. As system professionals, organization seems like the right thing to do and having these sets keeps our decisions organized. And as AI continues to copilot our work as if it was another human in the room, we need to meet its expectations too. We also need to verify that it’s doing the right thing with our meaty eyes.&lt;/p&gt;
&lt;p&gt;But if it’s just a system for you, as many design systems nerds tend to tinker with, maybe consider reducing your tokens and you might wind up over the hill.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/bell-curve.jpg&quot; alt=&quot;Bell curve of hard coding the values versus organizing your primitives&quot;/&gt;&lt;/p&gt;</content:encoded></item><item><title>Pretext review</title><link>https://blog.damato.design/posts/pretext-review</link><guid isPermaLink="true">https://blog.damato.design/posts/pretext-review</guid><pubDate>Mon, 30 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;This weekend a project called &lt;a href=&quot;https://github.com/chenglou/pretext&quot;&gt;pretext&lt;/a&gt; started making waves by &lt;a href=&quot;https://github.com/chenglou&quot;&gt;Cheng Lou&lt;/a&gt;. Here’s a gif that has been blowing up social media:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/pretext-dragon.gif&quot; alt=&quot;Directing a dragon with your cursor through a body of text&quot;/&gt;&lt;/p&gt;
&lt;p&gt;There’s no doubt about how impressive this demo is. The speed in which the text moves out of the way of the dragon is pretty incredible. As expected, many people are saying this is the end of CSS. So, let’s talk about it and address &lt;a href=&quot;https://chenglou.me/pretext/&quot;&gt;the demos provided that showcase some of the features&lt;/a&gt; in the lens of user experience.&lt;/p&gt;
&lt;h2 id=&quot;accordion&quot;&gt;Accordion&lt;/h2&gt;
&lt;p&gt;The first demo is of an accordion showcasing how the sections open and close smoothly without CSS hacks or measuring the DOM. This has been true for many years, we’ve wanted to animate from an intrinsic height for a long time. Well, we can do that now with pure CSS, in a few different ways.&lt;/p&gt;
&lt;p&gt;The first way was maybe a hack, which was to &lt;a href=&quot;https://nemzes.net/posts/animating-height-auto/&quot;&gt;animate the grid row&lt;/a&gt;. This was discovered 5 years ago. The difficulty with this approach is that it doesn’t work well with the native &lt;code&gt;&amp;lt;details&amp;gt;&lt;/code&gt; element.&lt;/p&gt;
&lt;p&gt;The second way is to use &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/interpolate-size&quot;&gt;&lt;code&gt;interpolate-size: allow-keywords&lt;/code&gt;&lt;/a&gt;. This allows you to animate between a &lt;code&gt;&amp;lt;length-percentage&amp;gt;&lt;/code&gt; value and an intrinsic size, &lt;code&gt;fit-content&lt;/code&gt;, or &lt;code&gt;max-content&lt;/code&gt;. This allows you to animate between &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;auto&lt;/code&gt; for the height.&lt;/p&gt;
&lt;p&gt;And finally, we have &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/calc-size&quot;&gt;&lt;code&gt;calc-size()&lt;/code&gt;&lt;/a&gt; which is a function I recently used on the new &lt;a href=&quot;https://mode.place&quot;&gt;Mise en Mode&lt;/a&gt; website to get the &lt;code&gt;auto&lt;/code&gt; size as a number that can be used in other functions, such as &lt;code&gt;round()&lt;/code&gt;. This also calculates the intrinsic size of the content, so it can be used to animate from &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;auto&lt;/code&gt; as well.&lt;/p&gt;
&lt;p&gt;As you might see when reviewing the MDN pages of these new CSS features, they don’t all have baseline availability yet. But do you really need JavaScript in order to animate the accordion? I’d argue you don’t, if you’re willing to put in a little extra effort learning what CSS has, and not ship some extra JavaScript for the sake of this.&lt;/p&gt;
&lt;h2 id=&quot;bubbles&quot;&gt;Bubbles&lt;/h2&gt;
&lt;p&gt;This is an interesting one. This is showcasing something called the “shrinkwrap” problem that is now more common than ever in a world of web chats. The problem is that CSS text wrapping isn’t efficient. The bubble that it leaves will have extra space not taken by text. What would be preferred is for the bubble to only be as big as the text needs to be. So without the shrinkwrap, each bubble is the same width. Meanwhile, with shrinkwrap, the bubbles match the size of the text leaving no extra space.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/bubble-wasted-pixels.png&quot; alt=&quot;Wasted pixels on text bubbles without shrinkwrap&quot;/&gt;&lt;/p&gt;
&lt;p&gt;There is a &lt;a href=&quot;https://kizu.dev/shrinkwrap-problem/&quot;&gt;CSS solution found by Roman Komarov&lt;/a&gt; to help with this problem which uses the new anchor positioning features. It also uses some pseudo element tricks to get the effect to behave. This is a pretty clever solution, but it is also pretty complex. It also doesn’t work in all browsers yet.&lt;/p&gt;
&lt;p&gt;The question is, do you want to bring in a JavaScript library just to get your text bubbles to shrinkwrap? Is this going to improve the user experience or is it an attention to detail that is not worth the cost of the extra JavaScript? I would argue the latter. The shrinkwrap problem is a problem, but it’s not a problem that is worth the cost of bringing in a JavaScript library to solve it. It’s a nice to have, but it’s not a must have.&lt;/p&gt;
&lt;h2 id=&quot;dynamic-layout&quot;&gt;Dynamic Layout&lt;/h2&gt;
&lt;p&gt;This looks like a magazine or editorial layout which has some images that are effecting the placement of the text. When I first saw this, I immediately thought of the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/shape-outside&quot;&gt;&lt;code&gt;shape-outside&lt;/code&gt;&lt;/a&gt; property which allows you to wrap text around a shape. Honestly, I haven’t used this CSS property much but I do know it takes some setup in order for it to work. You’d need to have an alpha of the shape so that text can wrap around it. The object needs to be set as a &lt;code&gt;float&lt;/code&gt; in order for the wrapping to occur. Placing that element could be a pain, requiring additional margins to be added, most likely with &lt;code&gt;shape-margin&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;What CSS won’t accomplish is the rotation of the images. For example, setting &lt;code&gt;rotate: 45deg&lt;/code&gt; on the image doesn’t affect the text wrapping around it. In the pretext demo, rotating &lt;em&gt;does&lt;/em&gt; affect the text. Ultimately, I imagine you could maybe animate a very complex polygon of points to follow on an interaction. But the reality here is that if you want this effect, JavaScript is the way to go.&lt;/p&gt;
&lt;p&gt;But do you want this effect?&lt;/p&gt;
&lt;p&gt;Even without the animation, when text doesn’t consistently start at the same place, it can become tiring to read. This is why we don’t typically center body text. Our eye wants to align to the left (or right in RTL languages) and when it can’t, it can be a bit of a strain. The additional rotation that can occur would make catching the word you were trying to read difficult since all the lines are recalculating their position on every frame. This is a fun effect, but it’s not something that I would add to an article because it’ll distract from the content and make it harder to read.&lt;/p&gt;
&lt;h2 id=&quot;variable-typographic-ascii&quot;&gt;Variable Typographic ASCII&lt;/h2&gt;
&lt;p&gt;As you might imagine, this isn’t meant for you to read the text. This is instead a artistic effect that uses glyphs to create a visual piece of art. Since there isn’t anything here that is specifically UX related, I’ll refrain from commenting on it, past hoping that someone puts an &lt;code&gt;aria-hidden=&amp;quot;true&amp;quot;&lt;/code&gt; on it so that screen readers don’t try to read that unintelligible mess.&lt;/p&gt;
&lt;h2 id=&quot;editorial-engine&quot;&gt;Editorial Engine&lt;/h2&gt;
&lt;p&gt;Similar to the &lt;a href=&quot;#dynamic-layout&quot;&gt;dynamic layout&lt;/a&gt;, this is a layout that has some images that are effecting the placement of the text. The difficulty in reading the text is much more apparent here because the balls are constantly moving around making the location of every word change on every frame. As said earlier, not something I’d use for something I’d want someone to read.&lt;/p&gt;
&lt;h2 id=&quot;justification-comparison&quot;&gt;Justification Comparison&lt;/h2&gt;
&lt;p&gt;I have to admit this has some practical use. The justification algorithm in CSS leaves a lot to be desired. It doesn’t do a good job of balancing the space between words and letters, which leads to large gaps appearing within the text called rivers. The pretext demos show a better way of balancing the text such that the rivers are reduced, even having tighter algorithms available.&lt;/p&gt;
&lt;p&gt;Though, one thing you’ll need to be careful of is the introduction of hyphenation. CSS has a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/hyphens&quot;&gt;&lt;code&gt;hyphens&lt;/code&gt;&lt;/a&gt; property that allows you to loosely control when words are hyphenated. If you have a better justification algorithm, you might find that you need to hyphenate more often in order to get the best results. This is something to keep in mind when considering this approach as I did when typesetting the book &lt;a href=&quot;https://mode.place&quot;&gt;Mise en Mode&lt;/a&gt; and ultimately decided to avoid justifying the text because of the potential for rivers and the need for hyphenation. I wanted to avoid both of those things in order to provide the best reading experience possible. I kept the content as the primary focus in a way that was familiar without stressing over the details of justification. Curating every small hyphen is very tedious. I personally rather keep the words intact and not have full justification.&lt;/p&gt;
&lt;h2 id=&quot;rich-text&quot;&gt;Rich Text&lt;/h2&gt;
&lt;p&gt;Again, I think this does have some practical use. &lt;a href=&quot;/posts/book-authoring-backstage/&quot;&gt;I’ve recently written about the difficulty in wrapping inline code accurately in CSS.&lt;/a&gt; In this demo, the inline code does wrap in a reasonable way but I’ll also say there’s configurations that make the wrapping a bit too eager.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/eager-wrapping.png&quot; alt=&quot;Wrapping has occurred too soon breaking the word docs&quot;/&gt;&lt;/p&gt;
&lt;p&gt;It might make some sense to add some &lt;code&gt;&amp;lt;wbr&amp;gt;&lt;/code&gt; spaces into the code at the right places. This could be done in a preprocessing step instead of on the client where the &lt;code&gt;pretext&lt;/code&gt; project needs to run.&lt;/p&gt;
&lt;h2 id=&quot;masonry&quot;&gt;Masonry&lt;/h2&gt;
&lt;p&gt;Ah yes, the layout everyone is waiting for. While &lt;code&gt;display: grid-lanes&lt;/code&gt; isn’t the property value we might have been expecting, the industry has been asking for a masonry layout for a long time. The pretext demo shows how to achieve this layout with JavaScript.&lt;/p&gt;
&lt;p&gt;While we’ve known that we’ve needed JavaScript to have dynamic masonry layouts &lt;a href=&quot;https://masonry.desandro.com/&quot;&gt;for a long time&lt;/a&gt;, there’s something you need to consider when implementing them; reading order.&lt;/p&gt;
&lt;p&gt;When you look at a masonry layout, what is the order of the boxes meant to be read in? Is it top to bottom, left to right? Or is it left to right, top to bottom? Maybe it changes due to one box being longer than another. If you inspect the demo you’ll see that some of the items are inserted in places that aren’t in any clear order. It is most likely using a dense packing algorithm to efficiently use the available space, but this isn’t necessarily how the items are meant to be consumed.&lt;/p&gt;
&lt;p&gt;The new &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/reading-flow&quot;&gt;&lt;code&gt;reading-flow&lt;/code&gt;&lt;/a&gt; property in CSS is meant to help suggest how these items are meant to be read. I’ll say with the amount of consideration the &lt;a href=&quot;https://www.w3.org/TR/css-grid-3/&quot;&gt;CSSWG has put into &lt;code&gt;display: grid-lanes&lt;/code&gt;&lt;/a&gt;, I’d trust that they’ve thought more about how masonry layouts should be managed more than “whatever fits best”.&lt;/p&gt;
&lt;h2 id=&quot;what-is-pretext-for&quot;&gt;What is pretext for?&lt;/h2&gt;
&lt;p&gt;It’s for people who want more control over how text flows; either for artistic purposes or for typesetting designers who crave the tools traditional print design has had for a long time. Just remember &lt;strong&gt;the web is not print&lt;/strong&gt;. Text has never animated on a magazine page, nor has that magazine page needed to download additional code in order for the layout to behave. These are different mediums even if we’ve made analogs to them over the years.&lt;/p&gt;
&lt;p&gt;I’m certainly not saying to avoid using the library, I think it’s fun and does have some practical use cases. But you should first consider your users and whether the features of this library are worth the cost of the extra JavaScript and the potential decrease in user experience. If you do decide to use it, make sure to use it in a way that enhances the content and doesn’t distract from it.&lt;/p&gt;
&lt;p&gt;This certainly isn’t the end of CSS, it’s showing what’s next.&lt;/p&gt;</content:encoded></item><item><title>Relearning line height</title><link>https://blog.damato.design/posts/relearning-line-height</link><guid isPermaLink="true">https://blog.damato.design/posts/relearning-line-height</guid><pubDate>Thu, 13 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;My wife and I were having an argument about line-height. It’s what happens when you live in a design systems house. She was working on updating some font properties and making a case for a larger line-height reflecting on the &lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/text-spacing.html&quot;&gt;WCAG guidelines 1.4.12 (Text spacing)&lt;/a&gt;. The guidelines were confusing so she also &lt;a href=&quot;https://designsystem.digital.gov/components/typography/#line-height&quot;&gt;found another reference within the United States Web Design System (USWDS)&lt;/a&gt; with the following quote:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Longer texts require more line height.&lt;/strong&gt; Headings and other content elements no longer than a line or two can have a line height between 1 (&lt;code&gt;line-height 1&lt;/code&gt;) and 1.35 (&lt;code&gt;line-height 3&lt;/code&gt;). Longer texts should have a line height of at least 1.5 (&lt;code&gt;line-height 4&lt;/code&gt;).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;I was shooketh.&lt;/strong&gt; I’ve never seen any mention of having the length of the line affect the size of the &lt;code&gt;line-height&lt;/code&gt; in the decades I’ve been working on the web. I’ve always seen it based on the &lt;code&gt;font-size&lt;/code&gt;. It’s the reason why the popular recommendation has been to use a unitless value.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.some-text&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;    /** 150% the font-size */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    line-height&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1.5&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, I immediately set out to disambiguate this and I was shocked at what I found. Read on in the comments. Just kidding.&lt;/p&gt;
&lt;p&gt;I found four sources that all mention that the &lt;code&gt;line-height&lt;/code&gt; should be affected by the length of a line; also known as the “measure”.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://pimpmytype.com/line-length-line-height/&quot;&gt;Pimp My Type&lt;/a&gt; “Longer lines need more line height, shorter lines need less.”&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.typographicwebdesign.com/setting-text/font-size-line-height-measure-alignment/&quot;&gt;Typographic Web Design&lt;/a&gt; “Depending on the amount of text, the line length, the font size, and the size of a font’s x-height,  you may find that the line height needs to be tightened or loosened slightly to promote comfortable reading.”&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fonts.google.com/knowledge/using_type/choosing_a_suitable_line_height&quot;&gt;Google Fonts Knowledge&lt;/a&gt; “There’s no secret formula for setting the “right” line height for type. It’ll depend on the font, the size it’s set at, the length of the line, and the overall reading context”&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.smashingmagazine.com/2009/08/typographic-design-survey-best-practices-from-the-best-blogs/&quot;&gt;Typographic Design Patterns And Best Practices&lt;/a&gt; “Leading (or line height) will always depend on your chosen font size and measure (or line length).”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In fact, that last article published by Smashing Magazine has some data about the typography from popular blogs. Here’s a copy of the data:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;line height (pixels) ÷ body copy font size (pixels) = 1.48&lt;/li&gt;
&lt;li&gt;line length (pixels) ÷ line height (pixels) = 27.8&lt;/li&gt;
&lt;li&gt;space between paragraphs (pixels) ÷ line height (pixels) = 0.754&lt;/li&gt;
&lt;/ul&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;The article and study are from 2009. 16 years in the past from when this post is being written.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;This got my wheels turning. While I know one of the articles said there’s no perfect formula, could we make something that has a general approximation to have a variable &lt;code&gt;line-height&lt;/code&gt; based on both &lt;code&gt;font-size&lt;/code&gt; and measure? In the year 2025, let’s see what we can do.&lt;/p&gt;
&lt;h2 id=&quot;minimums-and-maximums&quot;&gt;Minimums and maximums&lt;/h2&gt;
&lt;p&gt;We’ll want to use a &lt;code&gt;clamp()&lt;/code&gt; function for a rate of change and we’ll want to know what the minimum and maximum &lt;code&gt;line-height&lt;/code&gt; values will be. If we consider that paragraphs are typically the longest lines and the recommendation is supposed to be &lt;code&gt;1.5&lt;/code&gt;, we’ll make that the maximum. Headlines are typically shorter in terms of line length and often have a &lt;code&gt;line-height&lt;/code&gt; of between &lt;code&gt;1.1&lt;/code&gt; and &lt;code&gt;1.2&lt;/code&gt; so I’ll pick &lt;code&gt;1.15&lt;/code&gt; for the minimum. We’ll set these as variables because we’ll need them later.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.text&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --lh-min&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1.15&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --lh-max&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1.5&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    line-height&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; clamp&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--lh-min)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--lh)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--lh-max))&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where &lt;code&gt;--lh&lt;/code&gt; computes our &lt;code&gt;line-height&lt;/code&gt; depending on the width of the text container. Based on what we have so far, we’re looking to generate a value between &lt;code&gt;1.15&lt;/code&gt; and &lt;code&gt;1.5&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Before we get into measuring the width, I also want to touch upon another rule of thumb. It’s usually a best practice for you to limit the number of characters for any line. This makes larger amounts of text easier to read because your eye doesn’t need to travel as far when scanning for the next line. The range of acceptable characters for this length is anywhere between 40 and 80, so I typically pick 60 characters as an average.&lt;/p&gt;
&lt;p&gt;We’ll also want to pick a minimum number of characters. This is meant to denote the least amount of characters where the &lt;code&gt;line-height&lt;/code&gt; stops decreasing if the lines are too short. For this, I’d like to determine what the longest &lt;em&gt;common&lt;/em&gt; words are and count their characters. I don’t feel like accounting for “antidisestablishmentarianism” is realistic but accounting for “acknowledgements” is certainly reasonable. I couldn’t find a readily available list of these words since what common means is subjective. However, I did find a resource that lists long words of a certain number of syllables. I reviewed the lists and chose that &lt;a href=&quot;https://www.syllablecount.com/syllables/longest/four_syllable_words&quot;&gt;4 syllable words&lt;/a&gt; feel more common than &lt;a href=&quot;https://www.syllablecount.com/syllables/longest/five_syllable_words&quot;&gt;5 syllable words&lt;/a&gt;. The average number of characters from the words listed is roughly 18, so we’ll use that as our minimum.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;Note that you can make your own logical determinations for the minimums and maximums of these numbers. It’s very likely that you might feel that the growing &lt;code&gt;line-height&lt;/code&gt; begins too early at an 18 character width and opt to start growing later.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;h2 id=&quot;measuring-measure&quot;&gt;Measuring measure&lt;/h2&gt;
&lt;p&gt;Admittedly, it won’t be feasible with CSS alone to determine the length of each line of text, but we can get the largest width of an entire containing element of text. I’d argue that we actually don’t want each individual line to affect the &lt;code&gt;line-height&lt;/code&gt; for each line differently. That would make the vertical rhythm of a single paragraph very erratic. Getting the width of a container element is more reasonable and uniform.&lt;/p&gt;
&lt;p&gt;At first, I thought a container query would be the right direction. After all, we are trying to query the width of the text. However, there’s two problems with this. First, we’d need to query for every change that happens to the container, that would be like making a container query for every pixel and that isn’t realistic. Second, you can’t affect the container within the container query. This means we’d need some wrapping element as the container first, and then we could affect the text component in some way. However, that isn’t helpful since we really want to know the text component size. So how might we do this?&lt;/p&gt;
&lt;h2 id=&quot;time-for-a-hack&quot;&gt;Time for a hack&lt;/h2&gt;
&lt;p&gt;I found a post at Frontend Masters called “&lt;a href=&quot;https://frontendmasters.com/blog/how-to-get-the-width-height-of-any-element-in-only-css/&quot;&gt;How to Get the Width/Height of Any Element in Only CSS&lt;/a&gt;” which is precisely what we need to do. It uses a uninituitive trick with &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_scroll-driven_animations&quot;&gt;scroll-driven animations&lt;/a&gt; to achieve the effect. I highly recommend reading through the post if you want to learn some serious CSS magic. The tl;dr as I understand it is that as you resize an element, the amount allowed to scroll changes. That change will affect the scroll timeline and we use the amount if affects the timeline to determine the width. I could be wrong on that, I was just excited to have a working concept.&lt;/p&gt;
&lt;p&gt;For now, we want to grab the baseline of the effect with a few modifications. Let’s start with the &lt;code&gt;@&lt;/code&gt;-rules&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-keyword)&quot;&gt;@property&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; --_x {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  syntax: &amp;quot;&amp;lt;number&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  inherits: true;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  initial-value&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;: 0; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;@property&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; --ch {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  syntax: &amp;quot;&amp;lt;integer&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  inherits: true;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  initial-value&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;: 0; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;@keyframes&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; x { to { --_x&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;} }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is mostly identical to what is in the post, however I’ve changed the &lt;code&gt;--w&lt;/code&gt; variable to &lt;code&gt;--ch&lt;/code&gt;. This will represent the number of characters or the width of the containing element in terms of &lt;code&gt;ch&lt;/code&gt;. Now for the declaration block:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.text&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  --lh-min&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1.15&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  --lh-max&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1.5&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  --ch&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(1 &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--_x))&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  display&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; inline-block&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  overflow&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; auto&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  timeline-scope&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; --cx&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  animation&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; x linear&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  animation-timeline&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; --cx&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  animation-range&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; entry 100&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; exit 100&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  line-height&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; clamp&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--lh-min)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--lh)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--lh-max)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  )&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  &amp;amp;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;:before {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    content: &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    width&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;ch&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    display&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; block&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    view-timeline&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; --cx inline&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A few things are changed here, other than removing references to the y-axis. First, I’ve removed the &lt;code&gt;position&lt;/code&gt; properties because that can create new &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_positioned_layout/Understanding_z-index/Stacking_context&quot;&gt;stacking contexts&lt;/a&gt; and it doesn’t seem to change the final outcome. I’ve also set the &lt;code&gt;.text&lt;/code&gt; to be &lt;code&gt;inline-block&lt;/code&gt;. This is because block elements will just take up the width of their container. We want the amount of text to determine the size of the container. I’ve also updated &lt;code&gt;::before&lt;/code&gt; to have &lt;code&gt;width: 1ch&lt;/code&gt; which allows us to measure in terms of characters instead of pixels.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;Note that if this text element is in a flex container, you’ll want to set &lt;code&gt;align-self: start&lt;/code&gt; here also so this flex child doesn’t stretch and act like a block element. I’d even recommend that you use flex containers because making all text elements behave as inline will cause weird wrapping for shorter text. Using flex will ensure elements stack as expected.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;Now we’re ready for the final part, math!&lt;/p&gt;
&lt;h2 id=&quot;equation-of-a-line&quot;&gt;Equation of a line&lt;/h2&gt;
&lt;p&gt;Like my previous post that explored some &lt;a href=&quot;/posts/two-typographic-tricks&quot;&gt;advanced typographic tricks&lt;/a&gt;, we’re going to need to determine the rate of change here. We’re working linearly so we’ll need the same equations as before. First, the slope of the line.&lt;/p&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.css&quot; integrity=&quot;sha384-WsHMgfkABRyG494OmuiNmkAOk8nhO1qE+Y6wns6v+EoNoTNxrWxYpl5ZYWFOLPCM&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msub&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/msub&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msub&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/msub&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;m=(y_2-y_1)/(x_2-x_1)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;We can represent this in CSS like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.text&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --lh-min&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1.15&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --lh-max&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1.5&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --ch-min&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 18&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --ch-max&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 60&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --lh-delta&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--lh-max) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--lh-min))&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --ch-delta&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--ch-max) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--ch-min))&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --slope&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--ch-delta) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--lh-delta))&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where &lt;code&gt;--slope&lt;/code&gt; is the result. Next, we need to solve for the “b” part of equation. This is what I’ll call the &lt;code&gt;--offset&lt;/code&gt;.&lt;/p&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.css&quot; integrity=&quot;sha384-WsHMgfkABRyG494OmuiNmkAOk8nhO1qE+Y6wns6v+EoNoTNxrWxYpl5ZYWFOLPCM&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/msub&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/msub&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;b=y_1 - (m \times x_1)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7778em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;×&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;That is represented in CSS like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.text&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --lh-min&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1.15&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --lh-max&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1.5&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --ch-min&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 18&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --ch-max&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 60&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --lh-delta&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--lh-max) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--lh-min))&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --ch-delta&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--ch-max) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--ch-min))&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --slope&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--ch-delta) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--lh-delta))&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --offset&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--ch-min) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--slope) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--lh-min))&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And finally, we’ll use our restructured line equation to determine what the &lt;code&gt;line-height&lt;/code&gt; value should be based on the &lt;code&gt;--ch&lt;/code&gt; value.&lt;/p&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.css&quot; integrity=&quot;sha384-WsHMgfkABRyG494OmuiNmkAOk8nhO1qE+Y6wns6v+EoNoTNxrWxYpl5ZYWFOLPCM&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;x=(y-b)/m&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.text&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --lh-min&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1.15&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --lh-max&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1.5&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --ch-min&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 18&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --ch-max&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 60&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --lh-delta&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--lh-max) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--lh-min))&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --ch-delta&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--ch-max) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--ch-min))&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --slope&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--ch-delta) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--lh-delta))&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --offset&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--ch-min) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--slope) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--lh-min))&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --lh&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--ch) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--offset)) / &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--slope)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Putting these variables together with the earlier CSS gives you the demo below.&lt;/p&gt;
&lt;iframe height=&quot;500&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;CSS-Only, super easy screensize numeric pixel value width/height vars&quot; src=&quot;https://codepen.io/fauxserious/embed/VYwYjJx?default-tab=css%2Cresult&quot; frameborder=&quot;no&quot; loading=&quot;lazy&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/fauxserious/pen/VYwYjJx&quot;&gt;
CSS-Only, super easy screensize numeric pixel value width/height vars&lt;/a&gt; by Donnie D’Amato (&lt;a href=&quot;https://codepen.io/fauxserious&quot;&gt;@fauxserious&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’ve included a character counter at the end of the element so you can see the result of &lt;code&gt;--ch&lt;/code&gt;. I’ve also made the element &lt;code&gt;contenteditable&lt;/code&gt; so you can change the text right in the browser window. You should see the line height change with a &lt;code&gt;ch&lt;/code&gt; value clamped between &lt;code&gt;18&lt;/code&gt; and &lt;code&gt;60&lt;/code&gt;.&lt;/p&gt;</content:encoded></item><item><title>Screenreader only</title><link>https://blog.damato.design/posts/screenreader-only</link><guid isPermaLink="true">https://blog.damato.design/posts/screenreader-only</guid><pubDate>Sat, 27 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;I am a big proponent of component-driven development, and don’t agree with the &lt;a href=&quot;/posts/classname-soup&quot;&gt;utility class method of styling&lt;/a&gt;. In component-driven development, you offer blackbox abstractions of common implementations. Meanwhile, the utility class method allows for more customization. In a systematic approach, we want our experiences to be consistent and therefore follow the same patterns and conventions. Distributing these blackboxes that align with guidelines by default makes a consistent experience easy to create and manage. Whereas, trying to learn and follow guidelines from other resources to implement piecemeal comes with misintereptations and other inconsistencies.&lt;/p&gt;
&lt;p&gt;However, in this work there has been one concept that I’ve stuggled to put into this component-driven ecosystem; &lt;em&gt;screenreader only&lt;/em&gt; as it has traditionally existed as a class (eg., &lt;code&gt;.sr-only&lt;/code&gt;) added to an otherwise benign element.&lt;/p&gt;
&lt;h2 id=&quot;amongst-the-library&quot;&gt;Amongst the library&lt;/h2&gt;
&lt;p&gt;The purpose of screenreader only is to mark a section of an interface that is meant specifically for assistive technologies to pick up within the experience; invisible to sighted users. Here’s a common example:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;button&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;svg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        focusable&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        aria-hidden&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        viewBox&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;0 0 24 24&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;path&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        d&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;M19 6.41L17.59 5 12 10.59 6.41 5 5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;            6.41 10.59 12 5 17.59 6.41 19 12&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;            13.41 17.59 19 19 17.59 13.41 12z&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;svg&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;sr-only&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;Close&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, sighted users will be able to see the path of the &lt;code&gt;&amp;lt;svg/&amp;gt;&lt;/code&gt; in the shape of an ‘x’ with no other visual information. Non-sighted users who leverage assistive technology should receive “Close” from their tool and ignore the data set by the &lt;code&gt;&amp;lt;svg/&amp;gt;&lt;/code&gt;. There’s more about this composition and words about screenreader only versus &lt;code&gt;aria-label&lt;/code&gt; &lt;a href=&quot;https://gomakethings.com/revisting-aria-label-versus-a-visually-hidden-class/#pairing-a-visually-hidden-class-with-aria-hidden&quot;&gt;in this post&lt;/a&gt; by &lt;a href=&quot;https://twitter.com/ChrisFerdinandi&quot;&gt;Chris Ferdinandi&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;My gut reaction is that it would be odd to offer such a component that simply applies the styles required to make it hidden and for it to be offered as an exception to an otherwise utility-free ecosystem. However, I don’t like exceptions, I strive for consistent thoughtful systems.&lt;/p&gt;
&lt;p&gt;My first thought is where a &lt;code&gt;&amp;lt;ScreenreaderOnly/&amp;gt;&lt;/code&gt; would live amongst other components, if it is in fact a component itself. This is assuming that the library is vast and requires subsections that aim to direct visitors to the appropriate component through navigation. First I’d assume this might live with other “accessibility” components. However, this also assumes that folks are actively looking to include accessibility in their experiences; something that we can only dream of across an organization.&lt;/p&gt;
&lt;p&gt;Further, we might consider accessibility as a quality of components, perhaps not a component itself. As I’m having difficulty thinking about other possible memebers of this family that would also be associated with the &lt;code&gt;&amp;lt;ScreenreaderOnly/&amp;gt;&lt;/code&gt; component.&lt;/p&gt;
&lt;p&gt;My next thought is that because it is a quality, perhaps it isn’t a component but a property on an existing component we set. Because we expect that the content of this conceptual &lt;code&gt;&amp;lt;ScreenreaderOnly/&amp;gt;&lt;/code&gt; component to only ever be text, it might be safe to consider that it is a property of a text component.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Text&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; screenreaderOnly&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;To begin, start by...&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Text&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;&amp;lt;Text/&amp;gt;&lt;/code&gt; component will be widely more popular than the possible &lt;code&gt;&amp;lt;ScreenreaderOnly/&amp;gt;&lt;/code&gt; component, which will cause more folks to potentially visit its API and learn about this helpful feature. This being an opportunity to educate when its use is appropriate.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;In doing the research for this article, I wondered if anyone had considered rethinking “Screenreader Only” as “ARIA only” as it is a shorter name with perhaps better marketing. I do worry that a person would believe that it is a valid ARIA attribute (it’s not) but &lt;a href=&quot;https://fylgja.dev/components/aria-only/&quot;&gt;I’m not the first to consider the idea for the purpose&lt;/a&gt;.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;h2 id=&quot;when-is-it-appropriate&quot;&gt;When is it appropriate&lt;/h2&gt;
&lt;p&gt;I did quite a bit of reading and research before writing this post. As I’m an advocate for accessibility, I don’t consider myself an expert and definitely have areas of improvement in my practice. I wanted to know when the concept of screenreader only was appropriate if at all.&lt;/p&gt;
&lt;p&gt;For this topic, I highly recommend reading &lt;a href=&quot;https://twitter.com/scottohara&quot;&gt;Scott O’Hara&lt;/a&gt;’s post called &lt;a href=&quot;https://www.scottohara.me/blog/2017/04/14/inclusively-hidden.html&quot;&gt;Inclusively Hidden&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In Scott’s post, he describes some alternatives to screenreader only; specifically one loophole in particular.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;By attaching an &lt;code&gt;aria-describedby&lt;/code&gt; or &lt;code&gt;aria-labelledby&lt;/code&gt; attribute to a focusable element, and setting the ARIA attribute’s value to the completely hidden element’s id, screen readers will announce the content of the completely hidden element.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here’s his example:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;visually-hidden&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;example_desc&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  Here are specific instructions for the type&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  of information this form input is expecting to receive...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;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:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;example&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  Example&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;text&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;example&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; aria-describedby&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;example_desc&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this way, we still need to apply styles to the &lt;code&gt;.visually-hidden&lt;/code&gt; element in order for it to disappear from view. But this also demonstrates how to connect that content to an interactive element for further context by using &lt;code&gt;aria-describedby&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For completeness, here’s what Scott recommends as the styles for &lt;code&gt;visually-hidden&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.visually-hidden:not&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;:focus&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;:not&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;:active&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  clip&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; rect&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(0 0 0 0)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  clip-path&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; inset&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(50&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  height&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  overflow&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; hidden&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  position&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; absolute&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  white-space&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; nowrap&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  width&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’m now imagining some sort of interface for when &lt;code&gt;screenreaderOnly&lt;/code&gt; is used on the &lt;code&gt;&amp;lt;Text/&amp;gt;&lt;/code&gt; component to ensure it is connected to &lt;em&gt;something&lt;/em&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-comment)&quot;&gt;// Source&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; Text&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({ screenreaderOnly&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; children }) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;    /**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;     * We wouldn&amp;#39;t want to always add an id to all text&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;     * instead we&amp;#39;d add conditionally for screenreaderOnly.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;     * This is just for this example.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;     */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; React&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.useId&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-constant)&quot;&gt;    React&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.useEffect&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;        /**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;         * Consider appending the id instead of replacing&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;         * `aria-describedby` can accept space separated ids&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;         */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        screenreaderOnly&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;            ?.current&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;            ?.setAttribute&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;aria-describedby&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; id);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [screenreaderOnly&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; id]);&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:var(--astro-code-token-comment)&quot;&gt;    /**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;     * Assume additional logic to&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;     * bring-your-own HTML tag (BYOHTMLT)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;     * and force text node children.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;     */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;div&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;            className&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{ screenreaderOnly &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;visually-hidden&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;            id&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{ id }&amp;gt;{ children }&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    );  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-comment)&quot;&gt;// Usage&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; MyForm&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; useRef&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Text&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; screenreaderOnly&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{ ref }&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;            Here are specific instructions for&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;            the type of information this form&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;            input is expecting to receive...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Text&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;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:var(--astro-code-color-text)&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;example&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;            Example&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;text&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;example&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{ ref }&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However you feel about using a &lt;code&gt;useEffect&lt;/code&gt; to then use a DOM API to set an attribute that this component shouldn’t have control over is less important than the concept of connecting these two elements for accessibility purposes in an easy to use interface. It would be important to me that using &lt;code&gt;&amp;lt;Text screenreaderOnly&amp;gt;&lt;/code&gt; &lt;em&gt;requires&lt;/em&gt; the connection be maintained. It is too easy to accidentally rename &lt;code&gt;id&lt;/code&gt;s in a vast composition of components causing accessibility wiring to break.&lt;/p&gt;
&lt;p&gt;Also you can have your own naming convention to denote that the expected input is a &lt;code&gt;ref&lt;/code&gt; to the element that you wish to describe.&lt;/p&gt;
&lt;p&gt;It’s important to know that &lt;code&gt;aria-label&lt;/code&gt;, &lt;code&gt;aria-labelledby&lt;/code&gt; and &lt;code&gt;aria-describedby&lt;/code&gt; are not valid on all elements. &lt;a href=&quot;https://www.tpgi.com/short-note-on-aria-label-aria-labelledby-and-aria-describedby/&quot;&gt;The general gist is that these are meant for interactive elements or landmark elements.&lt;/a&gt; This interface above &lt;em&gt;could&lt;/em&gt; be enhanced to warn if the &lt;code&gt;ref&lt;/code&gt; is attached to an element that is inappropriate but would need some more conditional logic to identify this.&lt;/p&gt;
&lt;h2 id=&quot;why-aria-describedby&quot;&gt;Why &lt;code&gt;aria-describedby&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;The benefits of using &lt;code&gt;aria-describedby&lt;/code&gt; for screenreader only content is that first &lt;a href=&quot;https://www.aaron-gustafson.com/notebook/aria-quicktip-labelledby-vs-describedby/&quot;&gt;it doesn’t replace existing labeling&lt;/a&gt; (as &lt;code&gt;aria-labelledby&lt;/code&gt; would); it is meant to accompany it. It also benefits by auto-translation technologies that may struggle finding &lt;code&gt;aria-label&lt;/code&gt; content will &lt;a href=&quot;https://heydonworks.com/article/aria-label-is-a-xenophobe/&quot;&gt;more easily find &lt;code&gt;aria-describedby&lt;/code&gt; content&lt;/a&gt; because it is written within a discoverable DOM node.&lt;/p&gt;
&lt;p&gt;Certainly &lt;code&gt;aria-describedby&lt;/code&gt; isn’t &lt;em&gt;always&lt;/em&gt; going to be the correct solution. I believe if you’ve done due dilligence in crafting a well prepared experience, with semantic elements and appropriate attribute usage, this approach is probably going to help provide additional context to visually-impared users &lt;a href=&quot;https://adrianroselli.com/2019/10/stop-giving-control-hints-to-screen-readers.html&quot;&gt;for complex interfaces&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Know that if the content would also help visual users, you should absolutely consider putting the content inline with the composition and forego additional configuration complexity.&lt;/p&gt;
&lt;p&gt;And as always, reconsider the complexity of your experience overall, as you might be able to avoid cumbersome instructions for something simpler.&lt;/p&gt;</content:encoded></item><item><title>Spacing solved</title><link>https://blog.damato.design/posts/spacing-solved</link><guid isPermaLink="true">https://blog.damato.design/posts/spacing-solved</guid><pubDate>Mon, 09 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;Design tokens for color and typography are fairly common for design systems. In particular, color token naming has finally gotten some traction by thinking semantically. In other words, not naming the color based on the value but the intent to use. Typography is getting some traction here as well; where naming is done by use. This tends to be easier to understand since a type style is composed of many different properties.&lt;/p&gt;
&lt;p&gt;Spacing, on the other hand, has been locked into the original token naming scheme where the name of the token relates to the value of space; not the use. Tokens are either named using T-shirt sizing or numbers with a scale of several to use.&lt;/p&gt;
&lt;p&gt;The importance of using semantic tokens is to limit the decision making for the designer. The designer should focus on crafting the experience in a wireframe-like mindset. Color, typography, and other styles are noise that distracts from solving user problems. The design system should have the guidance to make clear decisions and reduce the noise.&lt;/p&gt;
&lt;p&gt;So the question is, how do we give meaning to spacing tokens?&lt;/p&gt;
&lt;h2 id=&quot;relationships&quot;&gt;Relationships&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.nngroup.com/articles/gestalt-proximity/&quot;&gt;Gestalt principle of proximity&lt;/a&gt; describes that elements that are close to each other are meant to be considered more related to each other than elements more far away. This is the principle we as designers are implementing when we decide the amount space used between elements.&lt;/p&gt;
&lt;p&gt;But how do we choose exactly how much space? Often times it’s looking at the whole page and picking what &lt;em&gt;feels right&lt;/em&gt; with a few constraints (like using multiples of 8 for the values). However, the system cannot give guidance about &lt;em&gt;feelings&lt;/em&gt;, it should have clear reasons as to why to choose an amount of space.&lt;/p&gt;
&lt;p&gt;The way I’ve identified an amount of space is by social relationships. &lt;a href=&quot;https://en.wikipedia.org/wiki/Six_degrees_of_separation&quot;&gt;Degrees of separation&lt;/a&gt; describes the way that entities are social connected to each other. We can think of parent-children or siblings that live in the same house to be 1 degree of separation from each other, while next door neighbors might be 2 degrees.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;I’ve explored the idea of describing space as degrees briefly and it doesn’t fit well. While there’s enough friction with the naming scheme to have users pause and read the guidance, it’s still using a scale to determine the space.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;Now, if we consider these entities as elements of an interface, the parent-child and sibling relationships translate. The parent &lt;code&gt;&amp;lt;ul/&amp;gt;&lt;/code&gt; element and its children &lt;code&gt;&amp;lt;li/&amp;gt;&lt;/code&gt; elements can have 1 degree of separation; meaning they are very closely related. While the &lt;code&gt;&amp;lt;ul/&amp;gt;&lt;/code&gt; element and its &lt;code&gt;&amp;lt;body/&amp;gt;&lt;/code&gt; ancestor element may not be as close.&lt;/p&gt;
&lt;p&gt;Keep this in mind as we review the next topic; density contexts.&lt;/p&gt;
&lt;h2 id=&quot;density-contexts&quot;&gt;Density contexts&lt;/h2&gt;
&lt;p&gt;I spent a great deal of time gazing at the first image in &lt;a href=&quot;https://medium.com/eightshapes-llc/space-in-design-systems-188bcbae0d62&quot;&gt;Nathan Curtis’s post about Spacing in Design Systems&lt;/a&gt;. Here’s the image from the post:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/nathan-curtis-space.png&quot; alt=&quot;Example cards&quot;/&gt;&lt;/p&gt;
&lt;p&gt;If we were to use the mental model we’ve come up with above, the tags within each card are 1 degree of separation apart from each other; in this comp a value of 8. The paragraph above is different from the tags, or in the next house. That can be described as 2 degrees of separation between the paragraph and tags.&lt;/p&gt;
&lt;p&gt;All of this works fairly well within the card, describing all the relationships of detail and space within. Where this is fuzzy is the cards themselves; each card is clearly an indentical sibling of the next and by our rules should have 1 degree of separation between. That was previously shown inside the card as 8, but here it is 32 and this &lt;em&gt;feels&lt;/em&gt; correct, but how do we describe this?&lt;/p&gt;
&lt;p&gt;The answer is density contexts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Every time we dive deeper into the content of the page, it is an opportunity to reduce the density of the area&lt;/strong&gt;. This would reduce the amount of space around and between elements but maintain the relationships we aim to describe.&lt;/p&gt;
&lt;p&gt;Let’s say, we start at the &lt;code&gt;&amp;lt;body/&amp;gt;&lt;/code&gt;. Lots of space between sections of the page because they are very unrelated. Maybe one section includes a card layout like the one above. We then shift the density down one notch and tighten the space between the children in this area. Going down into a card, we shift another notch down and tighten further showing that this content is most closely related.&lt;/p&gt;
&lt;p&gt;So each new density context defines the way space is used within that context. If you want less space between items because you want to show a close relation; add a new density shift and all the space within will reduce. This allows for the space between each card and the space between each tag to both be 1 degree of separation but the resolved value to be different because we are in a new density context.&lt;/p&gt;
&lt;p&gt;Now the designer chooses the density context for this particular experience but what about the actual token names? How do we give meaning to the locations where the values should be expressed?&lt;/p&gt;
&lt;h2 id=&quot;padding-and-gap&quot;&gt;Padding and gap&lt;/h2&gt;
&lt;p&gt;We can think of padding as the &lt;strong&gt;space around&lt;/strong&gt; an element and the gap as &lt;strong&gt;space between&lt;/strong&gt; elements. In the cards referenced within the image above, we can use these definitions to describe the spacing used in most of the elements.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Spacing between the tags is a gap.&lt;/li&gt;
&lt;li&gt;Spacing between the headings (video and supernova) is a gap.&lt;/li&gt;
&lt;li&gt;Spacing between the headings, paragraph, tags, and the button is a gap.&lt;/li&gt;
&lt;li&gt;Spacing between each card is a gap.&lt;/li&gt;
&lt;li&gt;All other spacing is padding.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each time the value of the gap changes signifies a density shift downward. First we start at a density where the gap equals 32, then we shift down (within the card) to a gap that equals 16, and finally we shift once more (inside each part of the card) where the gap equals 8.&lt;/p&gt;
&lt;p&gt;So do we just use token names that describe padding and gap? Almost.&lt;/p&gt;
&lt;h2 id=&quot;tying-it-together&quot;&gt;Tying it together&lt;/h2&gt;
&lt;p&gt;Going back to degrees of separation, I realized that trying to define larger degrees of separation would be difficult, especially when naming them with meaning. However, after compleing the exploration and identifying that there are really only two places where we need to apply space (around and between), that means I could reduce the number of spacing tokens down to 2 for most usage. That resulted in the following two names.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--spacing--near&lt;/code&gt;: often used to describe the spacing between elements showing close relation.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--spacing--away&lt;/code&gt;: often used to describe the spacing around elements showing less relation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I use near and away because there are areas where we want to use these values that aren’t confined to the guidance above. Buttons are the best example, where we want the space on the horizontal axis to be greater than the vertical. Setting &lt;code&gt;button { padding: var(--spacing--near) var(--spacing--away) }&lt;/code&gt; doesn’t break the mental model as much as if we used the word “gap” within the padding values for the button.&lt;/p&gt;
&lt;p&gt;And that’s it, you can create an interface in terms of relationships and density systematically with a very small number of design decisions with clear guidance. Below is a Codepen where I’ve recreated the card using this approach:&lt;/p&gt;
&lt;iframe height=&quot;500&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;Spacing context&quot; src=&quot;https://codepen.io/fauxserious/embed/dyJgzBM?default-tab=result&quot; frameborder=&quot;no&quot; loading=&quot;lazy&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/fauxserious/pen/dyJgzBM&quot;&gt;
Spacing context&lt;/a&gt; by Donnie D’Amato (&lt;a href=&quot;https://codepen.io/fauxserious&quot;&gt;@fauxserious&lt;/a&gt;)
on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;&lt;/iframe&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;h3 id=&quot;how-to-make-density-contexts-in-css&quot;&gt;How to make density contexts in CSS&lt;/h3&gt;&lt;p&gt;The approach to actually create density contexts in CSS is done by nesting CSS selectors and changing a variable at each level and recalculating what the spacing tokens mean at each.&lt;/p&gt;&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;scss&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;$attr-sel&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;[data-density-shift]&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;$levels&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;@function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; fib&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;($n) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  @return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;($n &amp;lt;= &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; fib&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;($n &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; fib&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;($n &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;@mixin&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; vars&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;($n) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  --spacing--away&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    #{&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;fib&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;($n &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1)} &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--density&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 0.5&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  )&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-color-text)&quot;&gt;  --spacing--near&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    #{&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;fib&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;($n)} &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--density&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 0.5&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  )&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;@for&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; $i &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; through&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; $levels {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  $nest-sel&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;($i == 1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;body&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; selector-nest&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;($nest-sel&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; $attr-sel))&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-color-text)&quot;&gt;  #{$nest-sel} {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    @include&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; vars&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;($levels &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; $i);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I’m using the &lt;a href=&quot;https://en.wikipedia.org/wiki/Fibonacci_number&quot;&gt;Fibonacci sequence&lt;/a&gt; for the steps since designers love that &lt;a href=&quot;https://www.nngroup.com/articles/golden-ratio-ui-design/&quot;&gt;golden ratio in layout&lt;/a&gt;.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;h2 id=&quot;-typography&quot;&gt;+ Typography&lt;/h2&gt;
&lt;p&gt;You can take this one step further by including typography. If you consider that each use of typography is included into a category, the type scale could ramp based on the density instead of in isolation. This allows for a clearer relationship between typography and space as many designers strive for through vertical rhythm and a grid system.&lt;/p&gt;
&lt;p&gt;If you identify categories of typography with proper guidance for each you can connect the density to the category. Body text becomes larger in hero images and smaller in general areas. Perhaps even smaller for data-dense interfaces like tables. Each area uses the same type style but the density changes the size.&lt;/p&gt;
&lt;h2 id=&quot;real-world-examples&quot;&gt;Real world examples&lt;/h2&gt;
&lt;p&gt;If you’re interested in how this all works in a real site or system, &lt;strong&gt;the &lt;a href=&quot;https://damato.design&quot;&gt;damato.design&lt;/a&gt; family of sites all use the above approach to determine spacing + typography&lt;/strong&gt;, including this site. I will admit determining where to add the density shift is the bigger challenge but what helps is to identify where the &lt;code&gt;--spacing--near&lt;/code&gt; and &lt;code&gt;--spacing--away&lt;/code&gt; values should go first, then determine if the density should shift as the second step.&lt;/p&gt;
&lt;p&gt;One more note, in the &lt;a href=&quot;https://system.damato.design&quot;&gt;DAMATO Design System&lt;/a&gt;, we do not have many typography categories; only display, heading, standard, and detail. This restricts the number of heading levels to only display and heading which loses content hierarchy unless shifting density. We could include more typography categories to describe a few additional levels (title, subtitle, etc) but opted to exclude for simplicity.&lt;/p&gt;</content:encoded></item><item><title>Spicy specifications</title><link>https://blog.damato.design/posts/spicy-specifications</link><guid isPermaLink="true">https://blog.damato.design/posts/spicy-specifications</guid><pubDate>Fri, 23 Jun 2023 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;Figma’s design conference &lt;a href=&quot;config.figma.com&quot;&gt;Config&lt;/a&gt; just ended and one of the biggest announcements is the introduction of &lt;a href=&quot;https://twitter.com/figma/status/1671563489457090560&quot;&gt;Variables&lt;/a&gt;. The reaction from the community is a mix of emotions. While many people were expecting Design Tokens, some can see the clear benefits of Variables while others are skeptical about perceived defiance to existing specifications. We’ll explore the current state of specifications for Design Tokens across the community and how Variables come into play.&lt;/p&gt;
&lt;h2 id=&quot;token-specifications-today&quot;&gt;Token specifications today&lt;/h2&gt;
&lt;p&gt;These are a few popular or relevant specifications that aim to describe the shape of a Design Token. While I haven’t completed an exhaustive search through existing systems with their own formats, the following examples will be enough to illustrate the current state of affairs.&lt;/p&gt;
&lt;h3 id=&quot;design-tokens-community-group&quot;&gt;Design Tokens Community Group&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.w3.org/community/design-tokens/&quot;&gt;Design Tokens Community Group&lt;/a&gt; (DTCG) is a collection of Design Tokens stakeholders from around the community representing design and development tools along with experts with working knowledge and experience in maintaining token libraries. The group has made some strides in a specification but it is very far from complete. The expectation is that all tools should adhere to this specification so that our representation of Design Tokens can be shared across tools. If there are deviations, a tool may skip a definition or fail. Here’s a basic example of a Design Token meant to describe a token &lt;code&gt;color-red-500&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    &amp;quot;colors&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;        &amp;quot;color-red-500&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;            &amp;quot;$type&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;color&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;            &amp;quot;$value&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;#f00&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://tr.designtokens.org/format/&quot;&gt;Reference&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is the core of the DTCG specification; a nested object with unique names. At the lowest nesting there should exist &lt;code&gt;$type&lt;/code&gt; and &lt;code&gt;$value&lt;/code&gt; keys; where the &lt;code&gt;$&lt;/code&gt; denotes a special key that is meaningful for tools to read. In the example, the tool should know that the &lt;code&gt;#f00&lt;/code&gt; is a color value and handle it accordingly. There are a few other keys and other more complex configurations, but this is the foundation that everyone is expected to follow.&lt;/p&gt;
&lt;h3 id=&quot;tokens-studio&quot;&gt;Tokens Studio&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://tokens.studio/&quot;&gt;Tokens Studio&lt;/a&gt; (built from a plugin project called &lt;a href=&quot;https://jansix.at/resources/figma-tokens&quot;&gt;Figma Tokens&lt;/a&gt;) has had a longer history of use (&lt;a href=&quot;https://github.com/tokens-studio/figma-plugin/releases/tag/0.1&quot;&gt;Jun 2020&lt;/a&gt;) than the first agreement provided by the DTCG (&lt;a href=&quot;https://www.w3.org/community/design-tokens/2021/04/17/first-editors-draft-shared-with/&quot;&gt;Apr 2021&lt;/a&gt;). This was to fill needs that were not solved within Figma at the time. Therefore, their specification is slightly different.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    &amp;quot;colors&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;        &amp;quot;color-red-500&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;            &amp;quot;type&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;color&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;            &amp;quot;value&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;#f00&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.tokens.studio/tokens/json-schema#multiple-files-storage&quot;&gt;Reference&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Note that the above is for a multi-file storage configuration. There are special keys expected at the first nesting level when using single-file storage. Also, note the absence of &lt;code&gt;$&lt;/code&gt; from the &lt;code&gt;type&lt;/code&gt; and &lt;code&gt;value&lt;/code&gt; which is not to DTCG specification today. &lt;a href=&quot;https://twitter.com/mikekamminga/status/1671572520955256849&quot;&gt;Mike Kamminga, Tokens Studio CEO, says&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We have been transitioning to fully support the DTCG proposal.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Importantly, to support more complex customer needs, Tokens Studio has included additional features that the DTGC specification has not yet provided. Continued from the previous quote:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;…we do fill some gaps where the proposed spec doesn’t provide solutions yet.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tokens-studio/resolver-spec/blob/master/schema.json&quot;&gt;An example of filling gaps&lt;/a&gt; comes in the form of token &lt;a href=&quot;https://tokens.studio/tools/resolvers&quot;&gt;resolvers&lt;/a&gt; which aim to describe complex relationships and conditionals which compute token values. While &lt;a href=&quot;https://github.com/design-tokens/community-group/issues/210#issuecomment-1553011810&quot;&gt;this has been suggested within the DTCG discussions&lt;/a&gt;, there are no official recommendations.&lt;/p&gt;
&lt;h3 id=&quot;specify&quot;&gt;Specify&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://specifyapp.com/&quot;&gt;Specify&lt;/a&gt; is a design token management tool that has been around before the DTCG and has had &lt;a href=&quot;https://web.archive.org/web/20190305103656/https://specifyapp.com/&quot;&gt;integrations with Sketch&lt;/a&gt; before Figma. A few weeks ago, &lt;a href=&quot;https://specifyapp.com/blog/specify-design-token-format&quot;&gt;they announced&lt;/a&gt; the Specify Design Token Format (SDTF). An excerpt from their example is below:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    &amp;quot;colors&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;        &amp;quot;color-red-500&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;            &amp;quot;$type&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;color&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;            &amp;quot;$value&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;                &amp;quot;default&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;                    &amp;quot;model&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;hex&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;                    &amp;quot;hex&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;#f00&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;                    &amp;quot;alpha&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://specifyapp.com/blog/specify-design-token-format&quot;&gt;Reference&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The standout part of the above is the &lt;code&gt;$value&lt;/code&gt; which is more descriptive than the others, containing more information about the value than only the string. As of today, this does not follow the DTCG specification but perhaps that’s by design. &lt;a href=&quot;https://twitter.com/nclsndr/status/1669374223914024962&quot;&gt;Nicolas André, Specify Senior Software Engineer, says&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The SDTF is not a file. The SDTF is designed to be a transport format between APIs that would eventually being configured by humans. To interact with it, we’ll use dedicated APIs lowering the underlaying complexity.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So the expectation here is that there are additional external systems that exist between APIs that expect this format.&lt;/p&gt;
&lt;h2 id=&quot;why-not-design-tokens&quot;&gt;Why not Design Tokens?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/pwnies/status/1671597246113280001&quot;&gt;Jacob Miller, Figma Product Manager, says&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Our reasons for naming it variables was primarily to align with development. Variables, much like css variables, is not just for design tokens, it’s also for conditional logic, string translations, etc.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;I disagree with the comparison to CSS, as &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/--*&quot;&gt;CSS Custom Properties&lt;/a&gt; are meant for style as Design Tokens are. I believe it would have been more accurate to compare using another language like JavaScript. Though I imagine the comparison was done to suggest how you might use Variables to result in style.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;The important takeaway here is that Variables can be used to describe our idea of Design Tokens but also to support additional needs which will most likely exist outside Design Token expectations. A clear example of this is content substitutions for localization. Design Tokens were not created to support this foundationally but Variables, &lt;em&gt;uniquely defined by Figma&lt;/em&gt;, can.&lt;/p&gt;
&lt;p&gt;For reference here is an example of a Figma Variable:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;   &amp;quot;id&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;&amp;lt;FIGMA_INTERNAL_VARIABLE_ID&amp;gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;   &amp;quot;name&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;color-red-500&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;   &amp;quot;resolvedType&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;COLOR&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;   &amp;quot;valuesByMode&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    &amp;quot;&amp;lt;FIGMA_INTERNAL_MODE_ID&amp;gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;#f00&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;   }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://www.figma.com/plugin-docs/api/Variable&quot;&gt;Reference&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is not a Design Token but Figma’s proprietary format meant for use within the Figma ecosystem. &lt;a href=&quot;https://github.com/figma/plugin-samples/blob/c91a1e2e02d6c6f100d7651d055ef84725adbb5d/variables-import-export/code.js#L136&quot;&gt;Based on the official plugin built to transform Variables into Design Tokens&lt;/a&gt;, the &lt;code&gt;valuesByMode&lt;/code&gt; will store several values by a unique identifier that relates to a mode. The mode could be light, dark, dense, Spanish, or many others and the value for this Variable can differ depending on the mode.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;&lt;a href=&quot;https://github.com/design-tokens/community-group/issues/210&quot;&gt;Jacob proposed&lt;/a&gt; how modes might look in the official DTCG specification. The discussion is one of the largest within the group and is currently unresolved.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;h2 id=&quot;a-deliberate-choice&quot;&gt;A deliberate choice&lt;/h2&gt;
&lt;p&gt;Figma has intelligently chosen the word “Variable” to opt out of following the specification to support its product features but also offers the import/export of the DTCG specification where appropriate against its Variables. I believe this is the correct direction as the DTCG learns from existing patterns. This allows Figma to go far beyond the responsibility of the specification in ways Design Tokens were never meant to be used.&lt;/p&gt;
&lt;p&gt;You could argue that Token Studio and Specify are also behaving in the same way. However, I fear their current offerings are confusing when compared with the DTCG. Again, Figma made a conscious decision to create a unique ecosystem to allow for new features to be built; &lt;strong&gt;Variables are not Design Tokens&lt;/strong&gt;. This is a subtle but important distinction as the other products create their own variations on top of an incomplete specification using conflicting methodologies. In other words, one cannot use a fully featured Tokens Studio file within Specify due to the incompatibility between specifications.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/design-tokens-spiderman.jpg&quot; alt=&quot;Will the real design tokens please stand up?&quot;/&gt;&lt;/p&gt;
&lt;p&gt;I believe the root of the problem is using the name Design Token for experimental approaches while a group aims to define what it means to be a Design Token. These other formats do not follow the specification in small and large ways and are therefore not accurate in describing Design Tokens as we expect them to be used in the community universally. Rebranding these novel approaches as something else for future features (as Figma has done) would make the expectations and responsibilities of Design Tokens more understandable to the community moving forward.&lt;/p&gt;
&lt;p&gt;I have empathy for the pioneers like Tokens Studio and Specify; existing before the specification makes this exceptionally challenging for them, borderline unfair. What Specify has done is a good start; creating a branded “flavor” of Design Tokens with the SDTF. I’d recommend Token Studio do something similar such as TSTF. In this way, it can be perceived that these approaches are Design Token &lt;em&gt;adjacent&lt;/em&gt; instead of wholly accurate to the community specification.&lt;/p&gt;
&lt;p&gt;Let me be clear, I support the advancements that all of these companies are providing for the Design Tokens community. They are heavily influencing the direction of the specification and we could not be where we are today without this work. I am being critical of what a Design Token is expected to be as it currently depends on where you get your tokens from. I have confidence that alignment will come, it’s simply a noisy time to get started.&lt;/p&gt;</content:encoded></item><item><title>Storefront &amp; Warehouse</title><link>https://blog.damato.design/posts/storefront-warehouse</link><guid isPermaLink="true">https://blog.damato.design/posts/storefront-warehouse</guid><pubDate>Thu, 02 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;I was speaking with a colleague recently about design system marketing. One of the problems I’ve seen is a person coming into design system resources and being immediately overwhelmed by the options. &lt;a href=&quot;https://lawsofux.com/hicks-law/&quot;&gt;Hick’s Law&lt;/a&gt; strikes again. I’m not just talking about looking at a code base. This is the case for popular public design systems too. As much as I admire Adobe’s work on Spectrum, it’s very easy to be intimidated by all of the stuff they have featured in their documentation.&lt;/p&gt;
&lt;p&gt;To illustrate this, I like to use an analogy that I call Storefront &amp;amp; Warehouse.&lt;/p&gt;
&lt;h2 id=&quot;getting-needy&quot;&gt;Getting needy&lt;/h2&gt;
&lt;p&gt;Let’s say you are looking for a new vacuum cleaner. You aren’t picky, you just need something that can clean dirt and pet hair from wood floors on occassion. You walk into a store, find a vacuum that looks good enough, and take it home. It work fine, nothing to be excited about. You got what you paid for and everything is good.&lt;/p&gt;
&lt;p&gt;Now, let’s say you do have some additional criteria for your vacuum. Maybe, you’d prefer that the vacuum was red to match the furnishings, so the appliance blends in better with the room it’ll be stored in. So you walk to the store, and you don’t see any red vacuums on the shelf. You find a stock person and ask if there’s any red vacuums in the back. He comes back and says that the company makes custom plates to change the color. All you need to do is order the plate and your vacuum will be red. So, you walk out with a regular vacuum and change it to be red afterward. You got what you were expecting, even though it took a little bit of extra work and everything is good.&lt;/p&gt;
&lt;p&gt;Now, let’s say you have a very specific desire. You want a vacuum in the shape of a standing lamp, so it really disappears when not in use, or better it can be used as a lamp while standing in the dock. You go to the store and look but there’s no vacuum like that on the shelf. You ask a stock person, if they have any in the back. This stock person loves the idea but knows that there’s no such vacuum in the warehouse. However, the warehouse does have all of the parts to make it. So, the stock person graciously gives you access to the warehouse so that you could build your own. It takes you a while to find all the pieces and figure out how to put them all together. In the end, you finally have precisely the vacuum you’ve been looking for and everything is good.&lt;/p&gt;
&lt;h2 id=&quot;struggling-at-the-store&quot;&gt;Struggling at the store&lt;/h2&gt;
&lt;p&gt;Instead of picturing something walking into a store and looking for a vacuum cleaner, think about it as a peer navigating to your design system resources looking for something they need. In some cases, it’s right there on the shelf. Some times it’s not quite what they need, but with a little configuration, it would be acceptable. And other times, a person would need to scour across different pages to collect the information needed to make exactly what they have in mind.&lt;/p&gt;
&lt;p&gt;There’s increasing struggles in these cases when we think about how we publish about documentation. For example, some documentation sites make you feel like walking directly into the warehouse. You see all the vacuum cleaner pieces but the ones that work off-the-shelf are mixed in with all the parts. It’s not immediately clear where to go for the thing you are supposed to work with. &lt;em&gt;There’s no storefront.&lt;/em&gt; I’d argue many large public design systems are guilty of this problem. With so many options, it’s hard to choose which is the best option as said earlier.&lt;/p&gt;
&lt;p&gt;For folks who find the resource that looks close, sometimes the options aren’t clear. It’s like going to the store and never finding help to let you know that you can customize your vacuum cleaner. Instead, you leave the store and go try another one, or get a vacuum from the shelf and paint it red. In either case, it would have been better if you were informed about the customizability right there on the unit when you first saw it. No need for a stock person to find, the options are clear.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;It also might not be great to have all of the options shown. That can also become overwhelming. Finding the right balance of popular usage and alternative configuration is tricky for sure.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;And finally, for folks that are immediately disappointed because they visit and don’t find anything that they need, this is the hardest to support. And unfortunately, this is something that I believe happens most often. With the rapid iterations of product design, no design system could possibly keep up with specific features. So, it is very common for people visiting resources to not have the time or experience to search for pages of documentation, tinker with some of parts, and craft something that aligns with the system. Often times, people believe it is faster to just make it without using the parts. I think with poorly documented design systems, this might very well be the case.&lt;/p&gt;
&lt;p&gt;Think about it. If the resources in the design system don’t align well with the visitor’s mental model. It’ll take time for that person to read the documentation, get an understanding of the approach and patterns, build something with the parts, and finally integrate with their application. On the other hand, if the person builds it &lt;em&gt;without&lt;/em&gt; adopting a new mental model, they still need to build the feature, it just might be with more individual parts. Importantly, these are parts they are familiar with. It’s that familiarity which equates to the speed of building and meeting the need of the product more quickly.&lt;/p&gt;
&lt;p&gt;That’s why so many resources often align with a person’s mental model instead of more unique presentations, even if that unique presentation is better in any way. It’s why early GUIs speak about a desktop and folders instead of a terminal and directories for the public. It aligns with existing mental models of working in the physical world. This means that introducing something better but novel will be most successful when alongside an existing mental model.&lt;/p&gt;
&lt;p&gt;In other words, if we’re going to offer a way to build the lamp-vacuum, when a person walks into the warehouse it should be immediately clear which parts they’ll need without being totally lost amongst all of the other unncessary parts.&lt;/p&gt;
&lt;h2 id=&quot;search-first&quot;&gt;Search first&lt;/h2&gt;
&lt;p&gt;Years ago, we had to walk through a store to find the place where they kept the vacuums. If I’ve been to the store before, maybe I remember where they’ve been kept. Hopefully, the store didn’t go through a redesign moving the items around, because my mental model of where the items are stored will make it faster for me to get to the thing I need.&lt;/p&gt;
&lt;p&gt;Now, some larger stores like Home Depot have their inventory locations available through their mobile site. You pick the location you are visiting, search for the item at that location, and the website will tell you where that item is in the store by aisle and bin. This way, you can go directly to the item you need without walking through the whole store, learning the layout, and hopefully landing on the thing you needed. This also avoids the possibility of you missing the item through the vast amount of aisles and products. You have confidence what you need is there and where it should be.&lt;/p&gt;
&lt;p&gt;This is why I find the exercise of creating navigation for a documentation site largely useless and potentially even harmful. Finding the thing you want is rarely useful in a wandering scenario. It is more helpful to zero-in on the resource you are looking for by aligning with your mental model. If you are from the UK and you look under “H” for hoover, you wouldn’t find any vacuums because the are listed under “V”. That would make the visitor assume that you have no vacuums because the information architecture doesn’t match their mental model, and &lt;strong&gt;they’ll leave empty handed because of your IA&lt;/strong&gt;. IA that was intended to help makes people leave disappointed.&lt;/p&gt;
&lt;p&gt;Meanwhile, a robust search experience could make the connection internally. Searching for hoover could alias to vacuums and produces the appropriate results. That way, searching could return results from the storefront first and warehouse after.&lt;/p&gt;
&lt;p&gt;This sort of search experience is common for icons, where a person looking for the “close” icon should return for the same result for “x”, “dismiss”, etc.. There are other systems that even let a person &lt;a href=&quot;https://shapecatcher.com/&quot;&gt;&lt;em&gt;draw&lt;/em&gt; the icon to provide results&lt;/a&gt;. We could imagine this expanding to components in our documentation sites.&lt;/p&gt;
&lt;p&gt;The hot take here, drop the exercise of figuring out the IA of your documentation site, and invest time in a robust search. In the world of artificial intelligence, leverage that to match mental models instead of deliberate aliasing. It would be best to meet people where they are, without causing them to visit external sites and learn opinionated IA. But if you don’t have the resources for AI, make search site-wide and fuzzy af. That gives your visitors access to the whole storefront and warehouse, but raises the most appropriate resources for their needs.&lt;/p&gt;</content:encoded></item><item><title>Storybook iframe tango</title><link>https://blog.damato.design/posts/storybook-iframe-tango</link><guid isPermaLink="true">https://blog.damato.design/posts/storybook-iframe-tango</guid><pubDate>Fri, 01 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;&lt;a href=&quot;https://storybook.js.org/&quot;&gt;Storybook&lt;/a&gt; is an essential part of design system development. It is considered an industry standard for creating components in isolation before they appear in production experiences. I’ve been working with the tool for nearly 8 years now and the team has really done a great job supporting the needs of our industry.&lt;/p&gt;
&lt;p&gt;That said, we got a problem.&lt;/p&gt;
&lt;h2 id=&quot;leaky-styles&quot;&gt;Leaky styles&lt;/h2&gt;
&lt;p&gt;I lean heavily into Storybook as a documentation platform. The product also went in that direction when introducing the ability to write stories as MDX. They’ve since walked back that approach in more recent iterations but, it is clear there is still a desire for writing documentation in the Storybook ecosystem.&lt;/p&gt;
&lt;p&gt;When stories appear within documentation pages, the styles used to customize the documentation have a tendency to leak into the stories. As an example, if you are relying on the default body color to cascade down in your component, the styles of the documentation will also loosely target some of these things. In cases where your stories are shown in a different mode from the storybook, this can have an unintended presentation.&lt;/p&gt;
&lt;p&gt;There’s a setting in Storybook that you can use which will create a barrier between the documentation styles and the stories.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; preview&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; Preview&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  parameters&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    docs&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      story&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { inline&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; false&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That configuration solves a problem, but introduces another one.&lt;/p&gt;
&lt;h2 id=&quot;out-of-the-frying-pan&quot;&gt;Out of the frying pan&lt;/h2&gt;
&lt;p&gt;The above setting renders each story in an &lt;code&gt;&amp;lt;iframe/&amp;gt;&lt;/code&gt; which is great for encapsulation, but awful for presentation. Specifically, the element does not know how big its content will be. Usually, this is a quick fix since the content of the frame is also the same domain as the page. We could just query inside the &lt;code&gt;contentWindow&lt;/code&gt; for the &lt;code&gt;body.scrollHeight&lt;/code&gt; and apply that amount to the &lt;code&gt;&amp;lt;iframe/&amp;gt;&lt;/code&gt;; problem solved!&lt;/p&gt;
&lt;p&gt;To do that, we first need to grab a reference to all the &lt;code&gt;&amp;lt;iframe/&amp;gt;&lt;/code&gt; elements. Normally, this is &lt;code&gt;document.getElementsByTagName(&amp;#39;iframe&amp;#39;)&lt;/code&gt; &lt;em&gt;except&lt;/em&gt; Storybook renders on the client-side. That is, these &lt;code&gt;&amp;lt;iframe/&amp;gt;&lt;/code&gt; elements don’t appear until later in the application lifecycle. So we have to wait until the page has these elements. Unfortunately, &lt;code&gt;DOMContentLoaded&lt;/code&gt; doesn’t work because that fires &lt;em&gt;before&lt;/em&gt; the hydration, same goes for the &lt;code&gt;defer&lt;/code&gt; keyword on the &lt;code&gt;&amp;lt;script/&amp;gt;&lt;/code&gt; tag. So how are we supposed to get these &lt;code&gt;&amp;lt;iframe/&amp;gt;&lt;/code&gt; elements?&lt;/p&gt;
&lt;p&gt;Enter my old friend, the Node Insertion hack. I first found &lt;a href=&quot;https://davidwalsh.name/detect-node-insertion&quot;&gt;this approach&lt;/a&gt; when working with registering web components. In fact, I speak about it within &lt;a href=&quot;/posts/fetching-definitions/&quot;&gt;my very first post&lt;/a&gt; in the blog. We can use the same approach to wait for &lt;code&gt;&amp;lt;iframe/&amp;gt;&lt;/code&gt; elements to appear and grab their reference. First, add the following CSS to the &lt;code&gt;manager-head.html&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-string-expression)&quot;&gt;iframe&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    visibility&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; hidden&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    animation&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; appear 0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;s&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; linear forwards&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;@keyframes&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; appear {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    to { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;visibility&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; visible&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, add a &lt;code&gt;&amp;lt;script/&amp;gt;&lt;/code&gt; tag in the same file with the following:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;window&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.addEventListener&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;animationend&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; onAnimationEnd);&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:var(--astro-code-token-keyword)&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; onAnimationEnd&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(ev) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;ev&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.animationName &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;appear&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        handleIframe&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;ev&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.target);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; handleIframe&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;($iframe) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    console&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.log&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;($iframe);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;this-is-not-the-element-you-are-looking-for&quot;&gt;This is not the element you are looking for&lt;/h2&gt;
&lt;p&gt;When you run storybook, you should get a log in the console that identifies an &lt;code&gt;&amp;lt;iframe/&amp;gt;&lt;/code&gt; element. When you dig a bit deeper, you’ll recognize that the element it returned is the preview &lt;code&gt;&amp;lt;iframe/&amp;gt;&lt;/code&gt;, not the one used for stories on a docs page. To get those &lt;code&gt;&amp;lt;iframe/&amp;gt;&lt;/code&gt; elements, you’ll need to listen &lt;em&gt;inside the preview&lt;/em&gt; also! Luckily, we can do this with a small change; update the &lt;code&gt;preview-head.html&lt;/code&gt; to include the same CSS that we added to the &lt;code&gt;manager-head.html&lt;/code&gt;. Let’s also update our &lt;code&gt;handleIframe()&lt;/code&gt; function:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; handleIframe&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;($iframe) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;$iframe&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.id &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;storybook-preview-iframe&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        $iframe&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.addEventListener&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;load&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; onLoad);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        onLoad&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.call&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;($iframe);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        adjustHeight&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;($iframe);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; onLoad&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    this&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;contentWindow&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.addEventListener&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;animationend&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; onAnimationEnd);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; adjustHeight&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;($iframe) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    console&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.log&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;($iframe);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, after you restart Storybook, the console should identify each individual Story &lt;code&gt;&amp;lt;iframe/&amp;gt;&lt;/code&gt;. The next part is what we’ve been waiting to do. We want to get the height of the internal &lt;code&gt;&amp;lt;body/&amp;gt;&lt;/code&gt; element and make the &lt;code&gt;&amp;lt;iframe/&amp;gt;&lt;/code&gt; respect the size of the content. Storybook applies the &lt;code&gt;height&lt;/code&gt; to the parent of the &lt;code&gt;&amp;lt;iframe/&amp;gt;&lt;/code&gt; so we’ll need to get that in the process.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; adjustHeight&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;($iframe) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; $body&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; $iframe&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;contentWindow&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;document&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.body;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; $parent&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; $iframe&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.parentElement;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; currentHeight&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; $parent&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.height;&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:var(--astro-code-token-keyword)&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (currentHeight &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;400px&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        $parent&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.height &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; $body&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.scrollHeight &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;px&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this function, we’re checking if the &lt;code&gt;&amp;lt;iframe/&amp;gt;&lt;/code&gt; is the default set by Storybook (&lt;code&gt;400px&lt;/code&gt;). If it is, we update the height based on the contents of the &lt;code&gt;&amp;lt;body/&amp;gt;&lt;/code&gt;. This allows you to set the &lt;code&gt;iframeHeight&lt;/code&gt; as a parameter is specific stories that should be a fixed height. This is helpful for stories that have content shifts, such as loading images.&lt;/p&gt;
&lt;h2 id=&quot;shadow-dom-when&quot;&gt;Shadow DOM when?&lt;/h2&gt;
&lt;p&gt;At this point, I’m pretty sure that all of this could be avoided if the stories were rendered within a Shadow DOM. Maybe once I get truly bored I could start looking to see how I might do that. But in the meantime, check out the new version of the &lt;a href=&quot;https://system.damato.design&quot;&gt;DAMATO Design System&lt;/a&gt; where I expect to publish real working examples of my approaches. It’s already been a big help in my regular discourse. More to come there over time.&lt;/p&gt;</content:encoded></item><item><title>UX Engineer, a terminal career</title><link>https://blog.damato.design/posts/terminal-career</link><guid isPermaLink="true">https://blog.damato.design/posts/terminal-career</guid><pubDate>Mon, 26 Dec 2022 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;In my teens, I was involved in many extra-curricular activities in high school. I was president of the art club for all 4 years and lead for the school’s robotics team. While I wasn’t officially part of the class counsel, due to my volunteer work especially with the homecoming floats, I was given a new title by my peers over 20 years ago; &lt;strong&gt;Design Engineer&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I didn’t think much of it then but after being fully immersed in both design and engineering, I resonate with that title. Not only do I consider how an experience could be constructed; I actually construct it. That’s something that’s always been important to me. Just having the idea wasn’t good enough, I needed to &lt;em&gt;show&lt;/em&gt; people the concept and it wouldn’t be complete unless it was the real deal.&lt;/p&gt;
&lt;h2 id=&quot;getting-paid&quot;&gt;Getting paid&lt;/h2&gt;
&lt;p&gt;It’s one thing to find your passion, it’s another thing for that passion to put bread on the table. My passion didn’t start doing that until after graduating college. My first engineering job was officially as the sole frontend engineer for a finacial tech company but they also didn’t have a designer. My co-workers saw how quickly I could prototype a design in &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt; and made it easy to collaborate, so they gave me the responsibility for the design of the platform too. That’s where I took on both roles but also had both titles; Product Designer &amp;amp; Frontend Engineer.&lt;/p&gt;
&lt;p&gt;After that role, I was hired at a real estate startup as a Frontend Engineer. The codebase was massive, they were using a framework I’ve never seen, and my onboarding buddy was assigned to a totally different team working on the launch of what would become the most successful product on the platform. It was a sea of anxiety and I had a metric ton of imposter syndrome. However, as timing would have it, they also hired a new Director of UX and we were in many of the same onboarding groups. I raised the idea of joining their team to help with prototyping and better integration of design into code and after some formalities, that’s how I became their first UX Engineer.&lt;/p&gt;
&lt;p&gt;I felt really relieved. Design was straightforward for me and I could ease my way into the codebase with small changes instead of feeling responsibility for the entire repository of code at once. Like many places, onboarding is not often crafted well because it’s done once and the business has other higher priorities. More on that later.&lt;/p&gt;
&lt;h2 id=&quot;rainbows--roses&quot;&gt;Rainbows &amp;amp; roses&lt;/h2&gt;
&lt;p&gt;Most of my first responsibilities were to prototype experiences to hand off for research studies. I quickly found that I was reusing the same assets over and over so I started making my own little library of components in CodePen. I could import files across pens by &lt;a href=&quot;https://blog.codepen.io/documentation/url-extensions/&quot;&gt;appending the file type to the end of the url&lt;/a&gt;. While there was an existing component library; these designs were often new and experimental. I needed my own collection of components that I could iterate on in isolation for these prototypes.&lt;/p&gt;
&lt;p&gt;Eventually, I became more comfortable with the codebase and found areas of improvement; especially when it came to CSS. I found out then that most engineers have difficulty with CSS. For me, CSS came naturally and I was able to do things that didn’t seem possible for others. As one example, there was an ask from design to pin the footer to the bottom of our listing results. The listing results component was using a collection of CSS overrides on &lt;a href=&quot;https://www.ag-grid.com&quot;&gt;AG Grid&lt;/a&gt;, and the architecture of those overrides were outlined in a multi-page document. It was a big deal to even look at the project, let alone change it. The lead engineer for the frontend team told management a change like this would take 6 weeks.&lt;/p&gt;
&lt;p&gt;I made the changes over 6 days.&lt;/p&gt;
&lt;p&gt;Eventually, I was responsible for all CSS found on the platform. While I wasn’t looking at every PR, I was always called into the room for large projects or complex experiences. The listing details page was one of my last large influences; which was one of the first places where I was able to use &lt;code&gt;display: grid;&lt;/code&gt; and &lt;code&gt;position: sticky;&lt;/code&gt; on a production site. I became responsible for the component library, as it eventually matured into a design system. By the end of my time, I was putting together the Design System team and looking into how we could support all the various frameworks being used with a singular source of truth.&lt;/p&gt;
&lt;h2 id=&quot;managing-expectations&quot;&gt;Managing expectations&lt;/h2&gt;
&lt;p&gt;While I loved all the work I was involved in, there was one thing that made me leave; lack of recognition. Many people were promoted during my tenure; I’ve seen some people promoted 3 times during my 2+ years there. I was promoted only once and it was title change with a cost of living pay increase. A few months later we’d have a new CTO and start new tech hubs around the world. What happened? Why was I left in the cold when everyone else was shining?&lt;/p&gt;
&lt;p&gt;When I first became a UX Engineer, I was reporting under the design organization. The trouble here was that our Director of UX didn’t have experience managing an engineer before. While this autonomy felt good to me, there was no career ladder. It wasn’t clear what steps I needed to take to be promoted. After the director left, I was reporting to the principle designer who really didn’t want to manage people.&lt;/p&gt;
&lt;p&gt;It was around this time the most senior frontend engineers were convincing me to come back into the engineering organization; right on the heels of the AG Grid work mentioned earlier. With some help from a new engineering manager willing to take me on, I moved back into the engineering organization. That manager was a huge help for my career because he understood my skills and influence and was able to be my voice in rooms I couldn’t be in. He was the person who fought for my promotion, just before he was pushed out by management.&lt;/p&gt;
&lt;p&gt;I was reporting under a new manager then; someone who previously identified as a backend engineer. It felt like I was reporting under the design team again. For our mandatory 1:1, he’d ask how I was doing and I’d just telling what I was working on. He really couldn’t give me much feedback because he didn’t know my world. It wasn’t really his fault; we were just paired poorly.&lt;/p&gt;
&lt;p&gt;When the new CTO came, we had a large restructuring which included new VPs of Engineering and other managers. After stating a case that I was a leader in the engineering organization, instead of receiving a promotion, I was restructured to report under one of the new VPs of Engineering. He really didn’t have any time for me; trying to get up to speed on larger problems that were happening with hyper growth. After having 6 managers and the company removing the only one that really helped me; I decided if I was going to grow, it couldn’t be here.&lt;/p&gt;
&lt;h2 id=&quot;picking-a-side&quot;&gt;Picking a side&lt;/h2&gt;
&lt;p&gt;After I left, I joined the company I currently work for. Here, the management understands my value and every person I’ve reported to can hold in-depth conversations about my areas of interest and provides meaningful feedback. It’s really what I’ve been looking for all along. There’s only one problem:&lt;/p&gt;
&lt;p&gt;My role is Software Engineer.&lt;/p&gt;
&lt;p&gt;What’s the difference? As a Software Engineer, you’re expected to just live in the code. You rarely get a glimpse into the experience design side of feature development and instead need to be responsible for lots of different engineered systems; databasing, CI/CD, bundling configurations, along with feature development. All the problems you solve have to do with getting the computer to do what you want with commands. As a UX Engineer, you are responsible for the user experience. The problems you are solving are user needs and (in my opinion) much more interesting and impactful.&lt;/p&gt;
&lt;p&gt;I don’t associate with being a Software Engineer. I associate with being a UX Engineer. However, because UX Engineering doesn’t have the career support that Software Engineering does; I need to masquerade as something I’m not just to succeed in a field and have a possibility of promotion.&lt;/p&gt;
&lt;p&gt;This isn’t only where I work. The industry has a clear problem supporting UX Engineering. Often a company has a UX Engineering role but reports under either design or engineering. This will often lead to the problems I’ve personally experienced shown above; lack of understanding about the role for existing management. On the other hand, folks picking a side can struggle because they don’t have all the knowledge or experience as other folks with roles aligned to the larger organization. In other words, a designer probably knows all the hidden gems in Figma; while a UX Engineer might only know some intermediate techniques. Without clear responsibilities; the UX Engineer will look subpar to the Designer. In my case, I’m not able to effortlessly debug workflow problems for CI/CD and unfortunately that sounds like something a Software Engineer should do.&lt;/p&gt;
&lt;p&gt;This is all assuming you were hired. The interview process can be especially disappointing for a UX Engineer. We’re often met with teams of Full Stack engineers who gang up on us to determine how much we don’t know about the stack. What good does knowing how to use Auto Layout in Figma do if you can’t even query a database?&lt;/p&gt;
&lt;h2 id=&quot;outlook&quot;&gt;Outlook&lt;/h2&gt;
&lt;p&gt;As an industry we should provide more support in UX Engineering. Even if there aren’t defined management positions leading UX Engineering in an organization; existing leadership should recognize this role and help define a path with folks that have these specialized skills; highlighting their abilities. These are the folks who translate design into code &lt;em&gt;without&lt;/em&gt; looking at the inspect panel. If you don’t see the benefit of that; I’m afraid you really don’t know how the web works.&lt;/p&gt;
&lt;p&gt;For my fellow UX Engineers out there, my heart goes out to you. I hope you’re being recognized for the work you’re doing; either by compensation, role, or fulfilling work. I wish I knew how to take the mask off. If you find out, please let me know.&lt;/p&gt;</content:encoded></item><item><title>Testing is hard</title><link>https://blog.damato.design/posts/testing-is-hard</link><guid isPermaLink="true">https://blog.damato.design/posts/testing-is-hard</guid><pubDate>Fri, 19 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;In my day job I code React components. React is a good solution to allow large teams to make significant applications fast and under a standardized set of rules. Without a library like React, the Javascript ecosystem would allow for many different ways of achieving a result. This makes it challenging for teams to gain traction.&lt;/p&gt;
&lt;p&gt;However, it doesn’t make it great for doing very specific things. Even things that you might think should be easy. This is often my frustration with testing library components, along with using a library to test that library. Yo dawg, I heard you like libraries.&lt;/p&gt;
&lt;p&gt;I’m using &lt;a href=&quot;https://www.cypress.io/&quot;&gt;Cypress&lt;/a&gt; for testing as it has a solid API and makes assertions in a true browser environment. I’m also using &lt;a href=&quot;https://www.chaijs.com/api/bdd/&quot;&gt;Chai’s expect API&lt;/a&gt; to help with the assertion.&lt;/p&gt;
&lt;h2 id=&quot;asserting-ref-placement&quot;&gt;Asserting ref placement&lt;/h2&gt;
&lt;p&gt;One of the biggest annoyances of learning React is not manipulating the DOM like I used to in the jQuery days. The DOM is very powerful, and we’ve got lots of awesome APIs in the browser that do all sorts of things. But React doesn’t want you to use any of those. One of my biggest pain points was getting an element to programmatically focus. To do that in React, you may have &lt;a href=&quot;https://react.dev/learn/manipulating-the-dom-with-refs#example-focusing-a-text-input&quot;&gt;seen something like this&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-keyword)&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; MyInputWithButton&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(props) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; inputRef&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; React&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.useRef&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;    function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; handleClick&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        inputRef&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;current&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.focus&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        &amp;lt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;            &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;props } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;ref&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{ inputRef }/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;            &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; onClick&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{ handleClick }&amp;gt;Focus the input&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        &amp;lt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, someone may want to supply their own &lt;code&gt;ref&lt;/code&gt;. That’s where &lt;code&gt;React.forwardRef()&lt;/code&gt; comes in. When we include this, things get more complicated.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; MyInputWithButton&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; React&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.forwardRef&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;((props&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; ref) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; inputRef&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; React&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.useRef&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    React&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.useImperativeHandle&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(ref&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; inputRef&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.current);&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:var(--astro-code-token-keyword)&quot;&gt;    function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; handleClick&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        inputRef&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;current&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.focus&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        &amp;lt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;            &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;props } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;ref&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{ inputRef } /&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;            &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; onClick&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{ handleClick }&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;                Focus the input&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;            &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        &amp;lt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We’ll need to merge the &lt;code&gt;ref&lt;/code&gt; that we made, with the one that is potentially incoming from outside. There’s &lt;a href=&quot;https://www.jameskerr.blog/posts/react-useref-and-forward-ref/&quot;&gt;other ways of merging refs&lt;/a&gt; but the point is that you’ll need to support this possibility if you allow the user to supply a &lt;code&gt;ref&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That’s all well and good. Now that we have this component in a library, how do we test it? Specifically, how can we be sure that the &lt;code&gt;ref&lt;/code&gt; is assigned to the &lt;code&gt;&amp;lt;input/&amp;gt;&lt;/code&gt; and not the &lt;code&gt;&amp;lt;button/&amp;gt;&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;This is exactly the problem I came across recently. A regression came in that caused that &lt;code&gt;ref&lt;/code&gt; to be assigned to more than one element by accident. So we want to be sure that wherever the &lt;code&gt;ref&lt;/code&gt; is meant to be assigned, it stays there.&lt;/p&gt;
&lt;p&gt;If you’re familiar with testing suites, you may think that this would a test that works:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;describe&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;ref assignment&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;    it&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;should assign ref to &amp;lt;input/&amp;gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;        const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; React&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.createRef&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        mount&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;MyInputWithButton&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{ ref } /&amp;gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        expect&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;ref&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;current&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.tagName).&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;to&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.equal&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;INPUT&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;// FAILURE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unfortunately, &lt;code&gt;ref.current&lt;/code&gt; is &lt;code&gt;null&lt;/code&gt; when written this way. In all my searching online, I couldn’t find any examples of folks testing if a &lt;code&gt;ref&lt;/code&gt; is assigned to the proper element. Luckily, &lt;a href=&quot;https://chatgpt.com/&quot;&gt;ChatGPT&lt;/a&gt; saved the day with the following test that will do what we want.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;describe&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;ref assignment&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;    it&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;should assign ref to &amp;lt;input/&amp;gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;        const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; React&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.createRef&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        mount&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;MyInputWithButton&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{ ref } /&amp;gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        cy&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.get&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;input&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.then&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(([$input]) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; expect&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;ref&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.current).&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;to&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.equal&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;($input)); &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;// SUCCESS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It seems that the secret is to first select the DOM element within the environment and after selection to assert that value against the &lt;code&gt;ref.current&lt;/code&gt;. Hopefully, this helps anyone else trying to assure that &lt;code&gt;ref&lt;/code&gt;s are assigned properly. I’m going to be adding similar tests in places where we expose the &lt;code&gt;ref&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;hover-styles&quot;&gt;Hover styles&lt;/h2&gt;
&lt;p&gt;If you thought that was fun, you’re going to love this next one. How might we test that styles appear on hover?&lt;/p&gt;
&lt;p&gt;You might think it’s just a matter of triggering a mouseover on the element. However, that only works if we’re triggering some Javascript execution. If we’re trying to test that styles are applied on &lt;code&gt;:hover&lt;/code&gt; using pure CSS, it’s not straightforward. There’s a plugin for Cypress called &lt;a href=&quot;https://github.com/dmtrKovalenko/cypress-real-events&quot;&gt;&lt;code&gt;cypress-real-events&lt;/code&gt;&lt;/a&gt; that tries to help get closer to true events. This is done by hooking into the &lt;a href=&quot;https://chromedevtools.github.io/devtools-protocol/&quot;&gt;Chrome DevTools Protocol&lt;/a&gt; to trigger events, but even this isn’t helpful enough for what we want. From the project’s &lt;code&gt;README.md&lt;/code&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Unfortunately, neither visual regression services like Happo and Percy nor plain cy.screenshot do not allow to test the hovering state. The hovering state is very different from any kind of js and css so it is not possible to capture it using dom snapshotting (like visual regression services do) and the screenshooting as well because cypress core itself is preventing hovering state in the screenshots.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The root cause of this problem is because hover is called a “Trusted Event”. This means &lt;em&gt;no technology can directly trigger a native CSS &lt;code&gt;:hover&lt;/code&gt;&lt;/em&gt;. The following is an excerpt from another post &lt;a href=&quot;https://reflect.run/articles/simulating-hovers-in-cypress/&quot;&gt;Simulating hovers in Cypress&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Events that are generated by the user agent, either as a result of user interaction, or as a direct result of changes to the DOM, are trusted by the user agent with privileges that are not afforded to events generated by script through the &lt;code&gt;createEvent()&lt;/code&gt; method, modified using the &lt;code&gt;initEvent()&lt;/code&gt; method, or dispatched via the &lt;code&gt;dispatchEvent()&lt;/code&gt; method. The isTrusted attribute of trusted events has a value of &lt;code&gt;true&lt;/code&gt;, while untrusted events have an &lt;code&gt;isTrusted&lt;/code&gt; attribute value of &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Most untrusted events will not trigger default actions, with the exception of the &lt;code&gt;click&lt;/code&gt; event. This event always triggers the default action, even if the &lt;code&gt;isTrusted&lt;/code&gt; attribute is &lt;code&gt;false&lt;/code&gt; (this behavior is retained for backward-compatibility). All other untrusted events behave as if the &lt;code&gt;preventDefault()&lt;/code&gt; method had been called on that event.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The post has some workarounds, but none of them truly solve the problem as everything is still Javascript-centric. What we really need is to get that CSS style tied to &lt;code&gt;:hover&lt;/code&gt; to show visually and be included in visual regression testing.&lt;/p&gt;
&lt;p&gt;In my search for a solution, I came across a project for &lt;a href=&quot;https://storybook.js.org/&quot;&gt;Storybook&lt;/a&gt; called &lt;a href=&quot;https://storybook.js.org/addons/storybook-addon-pseudo-states&quot;&gt;Storybook Pseudo States&lt;/a&gt; and it claims to “force” your components to display pseudo states like hover. While I am currently using Storybook for local development, it’s not part of the testing suite. So I wanted to know what they technique was under the hood.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/chromaui/storybook-addon-pseudo-states/blob/main/src/preview/rewriteStyleSheet.ts&quot;&gt;The file that is doing the magic&lt;/a&gt; is fairly overwhelming but there’s a simple way to think of what they are doing. You can even take a good guess at the file name (&lt;code&gt;rewriteStyleSheet.ts&lt;/code&gt;). Here’s the basic steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Get a reference to the element we want to assert hover on.&lt;/li&gt;
&lt;li&gt;Find the CSS that currently matches that element.&lt;/li&gt;
&lt;li&gt;Rewrite the &lt;code&gt;:hover&lt;/code&gt; selector to a non-pseudo selector.&lt;/li&gt;
&lt;li&gt;Apply the non-psuedo selector to the element.&lt;/li&gt;
&lt;li&gt;Profit.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There’s a lot that this addon is trying to cover past those steps. Seems like half the file is managing the &lt;code&gt;:host&lt;/code&gt; selector found in Shadow DOM contexts. This may also depend on how you have styles applied to your components. For my environment, the styles are written into &lt;code&gt;&amp;lt;style/&amp;gt;&lt;/code&gt; tags and there’s no Shadow DOM to worry about. This is what I did in my Cypress test:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; forceHoverSnapshot&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;($target&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;screenshotArgs) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; HOVER_ATTRIBUTE_SELECTOR&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;__data-cypress-hover__&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-comment)&quot;&gt;    // If our replacement stylesheet doesn&amp;#39;t exist&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;document&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.getElementById&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;HOVER_ATTRIBUTE_SELECTOR&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;)) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;        // Find the stylesheets that associate with the target&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;        const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; sheets&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;document&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.styleSheets]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.filter&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(({ cssRules }) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;            [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;cssRules]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.some&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({ selectorText }) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; $target&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.matches&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(selectorText));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;        // Concat all the cssText from associated styles&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;        const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; cssText&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; sheets&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.reduce&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;((css&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { ownerNode }) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; css &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;ownerNode&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;?.textContent &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-comment)&quot;&gt;        // Create and append new sheet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;        const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; $sheet&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; document&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.createElement&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;style&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        $sheet&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.id &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; HOVER_ATTRIBUTE_SELECTOR&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        sheets&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.at&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;ownerNode&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.after&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;($sheet);&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:var(--astro-code-token-comment)&quot;&gt;        // Append to replace instances of `:hover` with attribute&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        $sheet&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.textContent &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; cssText&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.replaceAll&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;:hover&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; `[&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;HOVER_ATTRIBUTE_SELECTOR&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;]`&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-comment)&quot;&gt;    // Add the attribute to the target element&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    $target&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.setAttribute&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;HOVER_ATTRIBUTE_SELECTOR&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-comment)&quot;&gt;    // Screenshot&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    screenshotArgs&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; cy&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.screenshot&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;screenshotArgs);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I imagine this would be helpful as a plugin in the future if it hasn’t been done yet. Knowing this, you &lt;em&gt;could&lt;/em&gt; opt to simply include a &lt;code&gt;[data-hover]&lt;/code&gt; selector to the same declaration as &lt;code&gt;:hover&lt;/code&gt; so it can be manually triggered. In fact, it might even make sense if you wish to present a “visually focused” state, typically used when keyboard navigating. For me, I don’t want to include code meant exclusively for testing in my production environment (👀 on &lt;code&gt;data-cy&lt;/code&gt; on public sites) so the extraneous selector is out of the question.&lt;/p&gt;
&lt;p&gt;So, that’s been the trouble with testing components recently. I know there’s been so many attempts at making testing our components easier over the years but sometimes it is an uphill battle for what seems like the smallest ideas that should have been tackled many times before. If I come across others, I’ll update this post. Good luck testing out there, it’s a battlefield!&lt;/p&gt;</content:encoded></item><item><title>Thanking you</title><link>https://blog.damato.design/posts/thanking-you</link><guid isPermaLink="true">https://blog.damato.design/posts/thanking-you</guid><pubDate>Wed, 02 Aug 2023 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;The &lt;a href=&quot;https://www.clarityconf.com/&quot;&gt;Clarity 2023 event site&lt;/a&gt; was just launched and folks visiting may notice that &lt;a href=&quot;https://www.clarityconf.com/person/donnie-damato&quot;&gt;I’ve been chosen to speak&lt;/a&gt; at the event. In the following thoughts I’ll attempt to describe why I believe this to be one of my most important achievements in my lifetime and express my deepest thanks for the upcoming opportunity.&lt;/p&gt;
&lt;h2 id=&quot;community&quot;&gt;Community&lt;/h2&gt;
&lt;p&gt;I’ve been a part of large, worldwide, internet-based communities in the past. The Dance Dance Revolution (DDR) community found at &lt;a href=&quot;http://www.ddrfreak.com/&quot;&gt;DDRFreak&lt;/a&gt; was said to be one of the top ten largest &lt;a href=&quot;https://www.phpbb.com/&quot;&gt;phpbb&lt;/a&gt; forums at its peak. During my time there I was one of the most frequent users with over 14,000 responses across the forums. Eventually the moderators took notice of my helpfulness in the DDR Simulators forum; which aligned with my interest in custom charts at the time and made me a moderator of that forum; and later the New York forum. I introduced a “contributor” status which helped users add content to the site after moderator review. I was also heavily involved in planning DDR tournaments in the New York area; including the &lt;a href=&quot;https://www.bloomberg.com/press-releases/2005-10-21/ziff-davis-digitallife-event-declared-a-major-hit-with&quot;&gt;DigitalLife&lt;/a&gt; event held at the Jacob Javits Center in New York City for 4 years.&lt;/p&gt;
&lt;p&gt;I mention this because I become obsessed with the community that I’m included within, and it shows. I love sharing ideas which improve our collective interests. I love helping people find the answers they need in areas where we’ve struggled previously. Talking to people without having to ramp them up with additional context gets to the root of the concept more quickly, and answers are more considerate when topical.&lt;/p&gt;
&lt;p&gt;With the decline of arcades, the DDR community has since transformed into something different that my old body simply cannot keep up with. I still play for fun and exercise and highly recommend it if you’ve never tried. I thank the moderators and DDR community at large for the opportunity to play such a significant role in leading discussions and events over those years giving me the experience to lead future communities.&lt;/p&gt;
&lt;h2 id=&quot;lightbulb&quot;&gt;Lightbulb&lt;/h2&gt;
&lt;p&gt;I returned to college in 2012, after dropping out ten years earlier. One of the courses I was taking was meant to emulate a production studio. One of the facets of the course was to spread the word about the shows we were producing. I had experience building websites, so I took it upon myself to design and code the first version. One of the adjunct professors who was brought in was the founder of a media company and suggested that more people are watching on their smartphones. This meant that the site would need to be redesigned with this in mind.&lt;/p&gt;
&lt;p&gt;This was my lightbulb and set me on my career path. The challenge that came with figuring out how to make content accessible to as many people as possible was engaging for me. I’ve always loved complex problems and attempting to create a solution which was as aesthetically pleasing as it was usable kept me deeply occupied in the practice.&lt;/p&gt;
&lt;p&gt;I thank &lt;a href=&quot;https://www.linkedin.com/in/georgeweiner/&quot;&gt;George Weiner&lt;/a&gt; who introduced me to responsive design.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;Another part of my coursework required me to interview an expert in my field of interest. It was only fitting that I reach out to &lt;a href=&quot;https://ethanmarcotte.com/&quot;&gt;Ethan Marcotte&lt;/a&gt;. I thank Ethan for his revolutionary design thinking and entertaining my less than profound questions.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;h2 id=&quot;thinking-in-systems&quot;&gt;Thinking in systems&lt;/h2&gt;
&lt;p&gt;I’ve written about &lt;a href=&quot;/posts/terminal-career&quot;&gt;my time as a UX Engineer&lt;/a&gt; before but, this is where I found the practice of designing systematically. In previous roles, I was in complete control of the look of the website. This was the first time where the experience of the product is separated by its features and in order to maintain a consistent appearance for users; a system of reusable design would emerge. I went on to learn more about the practice of the design systems here; soaking in all the information I could and learning from the folks who came before.&lt;/p&gt;
&lt;p&gt;It was at this time that I attended my first Clarity conference in 2018. It was an incredible event with all of these folks facing the same challenges that I was. I knew these were my people. There’s truly too many people to thank here, and I continue to learn from this community everyday.&lt;/p&gt;
&lt;p&gt;I thank &lt;a href=&quot;https://joe.sh/&quot;&gt;Joe Schmitt&lt;/a&gt; for the original concept of &lt;a href=&quot;/posts/tokens-as-intents&quot;&gt;Intents&lt;/a&gt; (semantic tokens) as well as &lt;a href=&quot;https://www.linkedin.com/in/maellegavet/&quot;&gt;Maëlle Gavet&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/jeniferv&quot;&gt;Jenifer Stewart&lt;/a&gt; for accepting me as the first UX Engineer at Compass.&lt;/p&gt;
&lt;h2 id=&quot;speaking&quot;&gt;Speaking&lt;/h2&gt;
&lt;p&gt;Since being involved in the community I’ve been exploring solutions for systematic design strategies; how might designers communicate intention in ways past semantic tokens. This has taken me to write works such as &lt;a href=&quot;https://gridless.design&quot;&gt;Gridless Design&lt;/a&gt; and &lt;a href=&quot;https://complementary.space&quot;&gt;Complementary Space&lt;/a&gt; which aim to understand the reason why we make design decisions and how to break traditions for the sake of scalable, inclusive needs.&lt;/p&gt;
&lt;p&gt;In 2022, &lt;a href=&quot;https://uxdx.com/&quot;&gt;UXDX&lt;/a&gt; asked me to speak on design systems at their annual UXDX conference in New York. This was the first time I was recognized outside my community as an expert in design systems. I thank their team for the opportunity and I highly recommend their conference.&lt;/p&gt;
&lt;p&gt;Since then I’ve been on a few podcasts: &lt;a href=&quot;https://www.youtube.com/@DesignSystemSocialClub/&quot;&gt;the Design System Social Club&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/channel/UCIjuF15MXSRY7ii8AwLz5RA&quot;&gt;UX Untamed&lt;/a&gt;, the &lt;a href=&quot;https://www.designsystemspodcast.com/&quot;&gt;Design Systems Podcast&lt;/a&gt;, the &lt;a href=&quot;https://www.youtube.com/@DesignSystemSocialClub/&quot;&gt;Design Systems Field Guide&lt;/a&gt;, and &lt;a href=&quot;https://www.fuegoux.com/podcast&quot;&gt;Fuego UX&lt;/a&gt;. All of these have been engaging discussions about design systems in real time and I thank all of these folks for inviting me on their shows.&lt;/p&gt;
&lt;p&gt;I’m looking forward to my first synchronous presentation about design systems at &lt;a href=&quot;https://www.dsw.community/&quot;&gt;DSW Day&lt;/a&gt; online. I thank &lt;a href=&quot;https://www.linkedin.com/in/mariaeguiluz/&quot;&gt;Maria Eguiluz&lt;/a&gt; for inviting me, for hosting DSW events for the past few years online and for &lt;a href=&quot;https://www.linkedin.com/feed/update/urn:li:activity:7090013258123784192/&quot;&gt;an absolutely stunning post highlighting some of my achievements&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As mentioned at the top of this entry, I’m more than excited to be on stage at Clarity this year and want to thank &lt;a href=&quot;https://www.jina.me/&quot;&gt;Jina&lt;/a&gt; for the opportunity. It is at this point I feel like a true expert in this field that I devote so much effort to, able to sit at the table with folks I’ve looked to years ago.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/ds-config.jpg&quot; alt=&quot;Myself sitting with Jina, Nathan Curtis, Kaelig Deloumeau-Prigent, and Connie Chen. Lunchtime at Config 2023&quot;/&gt;&lt;/p&gt;
&lt;h2 id=&quot;family&quot;&gt;Family&lt;/h2&gt;
&lt;p&gt;I most certainly need to thank my family for giving me the runway to have an art-adjacent career. Dropping out of college can be a concerning decision for parents but ultimately a path that put me where I needed to be. They still don’t understand what I do but that’s ok. They see the passion and that I’m living well on the results.&lt;/p&gt;
&lt;p&gt;Finally, I thank my wife &lt;a href=&quot;https://jennifer.damato.design/&quot;&gt;Jen&lt;/a&gt; for her support; the first to hear my convoluted design theories before they are fully-baked. While some folks don’t want to take their work home with them; I’m so incredibly lucky to be living in a design systems house.&lt;/p&gt;</content:encoded></item><item><title>The Daily Vibe</title><link>https://blog.damato.design/posts/the-daily-vibe</link><guid isPermaLink="true">https://blog.damato.design/posts/the-daily-vibe</guid><pubDate>Fri, 10 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;blockquote&gt;
&lt;p&gt;I vibe design/coded a design system in a few hours!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I see a post like this everyday on LinkedIn. In a world where AI is taking the industry by storm, it’s meant to show how powerful these tools are. But it also shows how little the industry understands about the work that goes into design systems.&lt;/p&gt;
&lt;h2 id=&quot;design-systems-are-for-people&quot;&gt;Design systems are for people&lt;/h2&gt;
&lt;p&gt;This is a quote by &lt;a href=&quot;https://www.jina.me/&quot;&gt;Jina Anne&lt;/a&gt; and the word “people” is important. First, a design system is not for a single person. It’s the reason why none of the sites I create have a design system. They have reusable resources, but not a system. The reason why they don’t have a system is because many of my personal projects are built by a single person; me. I don’t need to communicate the do’s and don’ts with anyone else. Do I have pieces of design systems like variables and components? Yes, but these things do not immediately make a design system. What I’m missing is what I find to be the defining quality of a system: &lt;em&gt;agreement&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;To get agreement, you need to have people. People who have different opinions on design, the way things should work, the way we represent ourselves. This is where the role of a design system maintainer comes in. Are we experts in tokens and components? Yes, but the hidden role that we discuss as a practice is that of a diplomat. We need to be able to communicate with different teams, different stakeholders, and different people. We need to be able to understand their needs and their perspectives, and synthesize that into a system that works for everyone. This is not something that can be done in a few hours, or even a few days. It takes time to build trust, to build relationships, and to build a system that people will actually use. I could have the perfect typography ramp in my eyes, but what good is it if it isn’t adopted? At best it’s a proof of concept or something for my personal work, but getting people to agree on it and use it, that’s the hard part. That’s the beginnings of a design system.&lt;/p&gt;
&lt;p&gt;So, if you made a styleguide for yourself in a few hours and that helps you visualize the plan for your project, that’s great! But I’d argue it isn’t a system unless you have stakeholders. People who can affect the decisions of the system, and people who can be affected by the decisions of the system. If you don’t have those people, then you don’t have a system. You have a styleguide, or a pattern library, or a component library, but you don’t have what I’d call a design system.&lt;/p&gt;
&lt;h2 id=&quot;how-to-vibe-a-design-system&quot;&gt;How to vibe a design system&lt;/h2&gt;
&lt;p&gt;Let’s say you want to really crack this nut. What does vibe creating a design system actually look like?&lt;/p&gt;
&lt;p&gt;From my perspective, the goal is to get the agreement of the stakeholders and make that available as a reusable resource. What this means is you need some way of collecting the decisions of the organization into a central location which is later used to inform design and development work over product lifecycles.&lt;/p&gt;
&lt;p&gt;One of the pieces to this puzzle is most likely some hosted &lt;a href=&quot;https://en.wikipedia.org/wiki/Model_Context_Protocol&quot;&gt;MCP&lt;/a&gt; server. This allows your AI tool to connect to a central location where it can look up resources of the design system in order to make informed decisions. This is the new “docs site” so to speak, except it’s not meant for humans to read, it’s meant for machines to read. This is where the agreement of the organization lives and how AI tools would reference what the agreements are for the organization. The challenge from here only becomes getting the organization to connect to the MCP using their tool of choice. This is no different from what we do today, promoting use of the system.&lt;/p&gt;
&lt;p&gt;The question is what does that agreement look like? Right now, there’s lots of talk about the &lt;code&gt;DESIGN.md&lt;/code&gt; file popularized by Google’s &lt;a href=&quot;https://stitch.withgoogle.com/&quot;&gt;Stitch&lt;/a&gt; project. This is a markdown file that is a hyped-up styleguide. It’s not a design system for the reasons we mentioned above. But it &lt;em&gt;could be&lt;/em&gt;. If that &lt;code&gt;DESIGN.md&lt;/code&gt; file was created by collecting the decisions of the organization, then that’s when it becomes a representation of a design system.&lt;/p&gt;
&lt;p&gt;The final piece to the puzzle is what getting agreement looks like. I’ve always said that a design system is a reflection of the people who use it. This means that if the organization wants purple gradient buttons, then it gets purple gradient buttons. However, other organizations have design systems teams that operate with stone tablets, carrying down the agreements from high atop a mountain of design wisdom. They might have gathered feedback from the organization, but the final decisions are curated by the design system team.&lt;/p&gt;
&lt;p&gt;In some of these cases, this is a good thing. This is the team responsible for making sure the resources provided by the system are of high quality and are consistent with the organization’s brand. In other cases, this can be a not-so-good thing. This can lead to a disconnect between the design system and the organization, where the design system is not actually serving the needs of the organization. This is where people outside of this team start going rogue, and where other decisions start making their way into the product without aligning to what was bestowed upon them. Stakeholders begin to take notice and might choose a side, defunding the design system because they are moving faster without it or because they vibed one up themselves. What’s so hard about making some color variables and a few components, especially now that generating them takes seconds? This isn’t agreement any longer, it’s just another vibe project gaining some temporary traction.&lt;/p&gt;
&lt;p&gt;The way to vibe a system is to capture what the organization is doing and making that available as a resource. This is the modern button audit. Traditionally, a design system blossoms from roaming around the product, gathering the decisions that have been made organically, and then making sense of those decisions as a collection of resources for the organization to use. This is that reflection idea from earlier. In areas where we find things in conflict, we get to the bottom of it. We ask stakeholders, complete research, and come to some conclusion on what the path forward is so that we’re all on the same page. Generally speaking, the design system team are moderators of that debate. We typically have very little stake in the outcome, as long as the final decision is beneficial to users. This is where we find out if the organization wants purple gradient buttons or not.&lt;/p&gt;
&lt;p&gt;So, what if the process of capturing the system was not a manual walk-around but a swarm of agents traversing the landscape of the product on a regular basis? As new decisions were made, they would be captured and considered a new design decision. This doesn’t necessarily mean that every small change is immediately a shared agreement, instead it provides a small amount of influence to how the design system evolves. As more people view other people’s decisions, they will themselves decide if that change they saw elsewhere is appropriate for them too. Now there’s &lt;em&gt;two&lt;/em&gt; places where that decision was made, gaining more influence on the design decisions. More people see this new direction and start adopting it, further influencing the decisions. Before long, the design system is truly reflecting what we’ve all individually decided to do. A &lt;strong&gt;self-fulfilling design system&lt;/strong&gt; that is truly a reflection of the organization, growing organically through the work that people are doing daily. This is the vibe design system, and it’s not something you can do in a few hours, but it is something that can be done with the right tools and the right approach.&lt;/p&gt;
&lt;p&gt;Admittedly, I don’t know what that looks like from a technical perspective. What does the infrastructure look at, how does it capture the decisions, and how do you fine tune the amount of influence each morsel of information has on the design system? What does the process of a rebrand look like? Do you turn the influence up to 11 for a specific file? I know some products are claiming that they take your existing system into account when vibing, but currently they are looking at existing resources. I don’t think any system is looking at the &lt;em&gt;product&lt;/em&gt; as a reflection of the system. But that’s &lt;em&gt;exactly&lt;/em&gt; what they should be doing. It’s what the design system team has been doing, or at least trying to do.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;I know what I’m proposing suggests that the design system team is no longer necessary. What I’d like to think is that it is no longer necessary &lt;em&gt;in the traditional role we’ve had&lt;/em&gt;. This is yet another example of how our industry is shifting in the world of AI. Design system practitioners need to re-adjust their positions. Change is uncomfortable, but it’s also an opportunity to grow and evolve. Our new role is not to be librarians but to be conductors. The music is going to play with or without us. We can help set the tempo.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;So, if you want to make a vibe design system, get it to look at the existing product and make the &lt;code&gt;DESIGN.md&lt;/code&gt; from that. That’s where the people are and their design decisions. Keep that up-to-date with how the people are working and the growth of the product. And the thing that you generated in a few minutes that you call a design system, it’s not. However, with a few people and some smarter infrastructure, it could become one.&lt;/p&gt;</content:encoded></item><item><title>The end</title><link>https://blog.damato.design/posts/the-end</link><guid isPermaLink="true">https://blog.damato.design/posts/the-end</guid><pubDate>Wed, 10 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;One of the concepts that bothers me about our practice is the amount of effort we put into tweaking designs. Where we only have a handful of designers visiting our products, we have thousands (if not more) of non-designers just looking to get something done. They aren’t thinking about how the button looks, they are hoping that it’s the last button click they need to finish a task.&lt;/p&gt;
&lt;p&gt;After so many years and billions of websites, we should have a very accurate understanding of how people expect the web to behave. So it would make sense to have components that are the canonical standard for a certain experience. We have some of these already on the web, such as the native HTML &lt;code&gt;&amp;lt;select/&amp;gt;&lt;/code&gt;. However, we often insist on knowing better. So we create custom versions of these with varying success. Maybe, we have too many items within that list and want to allow the user to more easily find options. There’s no native HTML element that handles this completely, so we’re invited to solve it for ourselves.&lt;/p&gt;
&lt;h2 id=&quot;global-design-system&quot;&gt;Global Design System&lt;/h2&gt;
&lt;p&gt;As mentioned in a talk and formally announced this week, &lt;a href=&quot;https://bradfrost.com/blog/post/a-global-design-system/&quot;&gt;Brad Frost is calling for a Global Design System&lt;/a&gt;. For folks who have managed design systems resources and reinvented wheels for several years, this seems like the obvious next move. An ultimate headless component library that only needs some values to present new expressions. The idea is taking what the &lt;a href=&quot;https://open-ui.org/&quot;&gt;Open UI Group&lt;/a&gt; is doing and truly standardizing it so we barely need to build interactive functionality from scratch again. The main work would then be mapping our brand expression (along with other design choices) to these existing resources.&lt;/p&gt;
&lt;p&gt;Many of the skeptics of this idea are worried that the implementation of this system wouldn’t match their current ideas. From my perspective, &lt;em&gt;I’m counting on that.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;There are countless examples of poor UX. These are often reshared as good because some larger company has done it. &lt;a href=&quot;/posts/hovercraft&quot;&gt;I’ve spoken about this problem before&lt;/a&gt;. This is where we get &lt;code&gt;&amp;lt;div role=&amp;quot;button&amp;quot;/&amp;gt;&lt;/code&gt; and other highly questionable decisions. We often believe that &lt;em&gt;our&lt;/em&gt; exception is justified when in reality we’re biased to our own beliefs about how an experience should behave. If we all agreed that a button should look like a button, act like a button, and legitimately be a &lt;code&gt;&amp;lt;button/&amp;gt;&lt;/code&gt;, the skeptics have no platform. In fact, we’d probably already have a Global Design System because we would all agree.&lt;/p&gt;
&lt;p&gt;But we don’t all agree and I think that’s because the folks that don’t also don’t have accurate data. Think of it like Flat Earth. Data is available that says &lt;code&gt;&amp;lt;button/&amp;gt;&lt;/code&gt; is the best way, but folks who don’t know the data challenge that notion and veer in a new direction looking for a new truth that they claim works just as well.&lt;/p&gt;
&lt;p&gt;So it would seem I’m a proponent of a Global Design System and I’d certainly be one. But I honestly think it’s too late.&lt;/p&gt;
&lt;h2 id=&quot;a-new-kind-of-interface&quot;&gt;A new kind of interface&lt;/h2&gt;
&lt;p&gt;I submitted a talk for Config last year which was about AI. At the time, AI was just emerging as the newest disruption in tech. While I certainly had plans to touch upon its upcoming impact in our daily work, I also wanted to touch upon the possibility of how we might consider the effects for the larger population outside of design. Remember, we design products for people; all people at best. So I wanted to explore what AI might mean for folks in their normal day-to-day. As you might know, I wasn’t accepted to present that exploration but as always actions speak louder than words.&lt;/p&gt;
&lt;p&gt;There’s been some buzz at this year’s &lt;a href=&quot;https://www.ces.tech/&quot;&gt;CES&lt;/a&gt; about AI, and much about a new company called &lt;a href=&quot;https://www.rabbit.tech/&quot;&gt;Rabbit&lt;/a&gt;. I recommend that you watch the Keynote on their website, especially if you are a design systems practitioner. If you’re like me, you should have some strong opinions about what is next for us within the first few minutes.&lt;/p&gt;
&lt;p&gt;The idea is that this technology has introduced the concept of a LAM (Large Action Model), which is meant to understand how user interfaces work and can execute tasks on them in the same way a person might. This means that there’s no need for a service to have an API to hook into, and no need to connect services together for chained commands. In this voice-activated experience, the end-user doesn’t even see the interfaces that are being worked on. They just need to confirm that the results were expected.&lt;/p&gt;
&lt;p&gt;If you don’t understand what this means for us, I’ll make it clear. The introduction of LAMs could be &lt;strong&gt;the end of our practice as we know it.&lt;/strong&gt; If the public only needs to interface using their voice to complete a task on your product, what the GUI looks like is meaningless. &lt;em&gt;There is no value to the look if the user never sees it.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-do-we-do-now&quot;&gt;What do we do now?&lt;/h2&gt;
&lt;p&gt;This is the question we need to ask. Not, what’s the best design token naming convention? Or, how to support perfect nested rounding on corners? As a design systems expert, &lt;em&gt;what expertise can I offer in the field of non-graphical interfaces?&lt;/em&gt; Personally, I don’t have an answer for this yet but, you can be sure I’m thinking about it.&lt;/p&gt;
&lt;p&gt;Importantly, I also don’t believe this is a change that will happen very soon. VUIs are still in their infancy in comparison to GUIs. Interpreting natural language requires much more computational work than having a user choose to click a button. That process of identifying a user’s intention and translating it to an action on a customized interface that our brain would normally handle is now being handled by a LAM. This would mean that people would need access to that computing power and is not wholly accessible worldwide. The human brain currently requires fewer resources and has a better means of understanding, so it remains the primary actor in the field of user experience.&lt;/p&gt;
&lt;p&gt;Another way to think about it is offloading the complexities of user experience onto systems, reducing the user experience to nearly zero. But what about those moments of delight, you say? Now experiences are lifeless! This is where art has been confused with design. The user experiences being targeted are task-based and tasks are commonly not fun. We’ve added moments of delight to make them feel like they aren’t tasks. Your product has been a necessary hindrance that you’ve made slightly more fun through small moments. However, this concept considers removing the tasks entirely. So the delight that the user is looking for is accurately not your product, but some hobby or IRL experience instead; like seeing art for fun. Imagine the amount of time saved planning a trip when you don’t get lost in the number of tabs you have open, doing cross-site comparisons, and trying to navigate the same data displayed in different ways because of branding or some other design bias. Time to spend doing things that are &lt;em&gt;actually&lt;/em&gt; fun.&lt;/p&gt;
&lt;p&gt;So, take a moment from color shades to think about the future. Our users will thank us for it.&lt;/p&gt;</content:encoded></item><item><title>Thinking Full Stack</title><link>https://blog.damato.design/posts/thinking-full-stack</link><guid isPermaLink="true">https://blog.damato.design/posts/thinking-full-stack</guid><pubDate>Mon, 16 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;A large part of the role for design system maintainers is to make things for your peers. This comes with having empathy for your organization and the people who compose it. Many organizations are composed of engineers that are jacks-of-all-trades. The idea of having a developer that can manage the front &lt;em&gt;and&lt;/em&gt; the back-end seems very appealing to organizations. Especially since CSS is so easy, we don’t even need to test for it! 🫠&lt;/p&gt;
&lt;p&gt;Enter the &lt;em&gt;full-stack engineer&lt;/em&gt;. Where you work probably has a lot of them, some companies might even highlight “we’re all full-stack here” with varying degrees of prowess. As design system maintainers we are often adjusting our strategies to fill in the gaps of full-stack knowledge. The CSS skill that wasn’t assessed in the interview? Don’t worry, we have a design system for that.&lt;/p&gt;
&lt;p&gt;In this post, I want to explain something to full-stack engineers that is often confusing: why can’t I just declare that the button is blue?&lt;/p&gt;
&lt;h2 id=&quot;the-button-is-blue&quot;&gt;The button is blue&lt;/h2&gt;
&lt;p&gt;You get a mockup from your designer for a shiny new button. You look at the carefully crafted specifications and start coding. It’s just a button, so no worries about complex structure. But you know there’s probably a lot of states, so you’ll definitely be writing some CSS. If you’re lucky, your team is leveraging Tailwind which makes it easy to declare all of the styles right there in the structure. You don’t need to think of a container name for the styles, you can just say &lt;code&gt;className=&amp;#39;bg-blue-500&amp;#39;&lt;/code&gt; and the button is now blue. Perfect!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blue-button-first-color.png&quot; alt=&quot;Developer making a button for the first time&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Some time passes and changes happen in the design. The button isn’t performing well so we need to change it. You get a new design and see it is just some color changes. You get back into those Tailwind classes and start making adjustments. Toggling states in Storybook, updating visual regression tests, and anything else that was affected by the update. It’s not as time consuming as when you first created the button, but it’s not a simple find and replace. You create the PR, get the sign off from your other team members and get the change in the deploy pipeline. Back to your regularly scheduled tickets.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blue-button-pipeline.png&quot; alt=&quot;Developer making changes to the button for the first time&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Some more time passes and the head of marketing pings your team about a special promotion that we need to run for 2 weeks, which is cobranded with another partner. We need a few new pages made that have buttons but they need to look different than the other ones because they need to show this new cobranded presentation. It takes too much time to make a wholly new button, so you want to make some quick overrides to the original one for this special purpose. Again, you go through the motions of updating classnames, maybe even making a special “promo” variant because this isn’t the first time you gotten this kind of request. Now the button’s variants are getting numerous: primary, secondary, critical, info, highlight, promo. Each of them has slight differences, some of which we don’t even know if they are still being used. You get the change in the pipeline, and it’s ready for use in the promotional pages. The promotion was a huge success, and now we have to tear it down. It doesn’t make sense to go into the button and remove the code, I have more important things to take care of. We’ll write a ticket and put it in the backlog.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blue-button-variants.png&quot; alt=&quot;Developer maintaining variants for button&quot;/&gt;&lt;/p&gt;
&lt;p&gt;A new designer comes on board and is in charge of a fresh new look but they aren’t familiar with the current state of affairs. They’re exploring things in their design tool, and aren’t organized yet. They want to see how changes they make would look in real applications. You know we don’t really have a good way of doing that. Each design change has to be coded, tested, reviewed, and deployed. The process takes a while so it’s really hard to iterate on how a design decision could affect the current experience. All you could recommend is to try things in design and then you’ll make changes in the code to match. Luckily, you have some auto deployed Storybook that can give an idea of what things might look like, but we’ll never really be sure until it’s out in the wild. Even then, we might find oversights that we’ll require a rollback and re-release. All of it taking time away from more important infrastructure work that you were actually assessed on in your original interview.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blue-button-new-designer.png&quot; alt=&quot;Developer working with a new designer&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Wouldn’t it be better if the person who wanted to make these little design changes could just do it themselves?&lt;/p&gt;
&lt;h2 id=&quot;in-the-code&quot;&gt;In the code&lt;/h2&gt;
&lt;p&gt;Let’s say you have the following JSX code:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-keyword)&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; Button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({ variant&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;props }) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;props } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;className&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{ &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;clsx&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;        &amp;#39;bg-blue-500&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; variant &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;primary&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    }) }&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And you might say, toggling classes with &lt;a href=&quot;https://www.npmjs.com/package/clsx&quot;&gt;&lt;code&gt;clsx&lt;/code&gt;&lt;/a&gt; is old news, we use &lt;a href=&quot;https://cva.style&quot;&gt;&lt;code&gt;cva&lt;/code&gt;&lt;/a&gt; now. Ok, here’s the same thing with &lt;code&gt;cva&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; cva&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({ variants&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    variant&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { primary&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;bg-blue-500&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;] }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;} });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Under the hood, providing the concept of &lt;code&gt;primary&lt;/code&gt; is still applying a declarative class that directly represents the blue background for the button.&lt;/p&gt;
&lt;p&gt;But maybe you have a more sophisticated system. Maybe you have a global palette that’s type-safe and ensures only the colors that are meant to be applied can be used. Here’s how this might look using &lt;a href=&quot;https://panda-css.com/&quot;&gt;Panda CSS&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-keyword)&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; Button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({ variant&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;props }) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;props}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;            className&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{ &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;css&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({ bg&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;blue.500&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; }) } /&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In all of these cases, the person coding the button is ultimately in charge of the way it is presented. Sure, someone else told them to use &lt;code&gt;bg-blue-500&lt;/code&gt;, but that will never make it to production and get in front of users without the developer interpreting that change in code. Even though they aren’t the person who made the decision about what color this should be, it is the developer’s responsibility to maintain the application of this color to the element. Every little decision that a designer, marketer, or other stakeholder might want is gated behind the developer.&lt;/p&gt;
&lt;p&gt;In my view, the full-stack developer is not a stakeholder in the final presentation of the button. So it doesn’t make sense that they should have the responsibility of maintaining how it looks. Instead, we should provide some proxy that allows the decision from a stakeholder to be made by the stakeholder. Delegating the responsibility about the color of the button to the people who actually care what the button looks like. That leaves the developer open to tackle the engineering tasks that they were trained to do.&lt;/p&gt;
&lt;p&gt;So, how could we let a stakeholder apply the color they want to these buttons? We’d need some way of allowing their decision to be restricted to only design properties, and ensure nothing else is affected.  We can’t just make this another prop. Props are used by developers so other non-developers won’t use them. We need a list of all the design decisions that we expect stakeholders want to change, and allow them to assign values to those in some curation exercise. Then our components could look up the values they assigned and apply those assigned values to the associated properties.&lt;/p&gt;
&lt;h2 id=&quot;new-naming&quot;&gt;New naming&lt;/h2&gt;
&lt;p&gt;Ok cool, so let’s try using what we have to make this. First we set up some list that people can use to change the values that are assigned. Let’s assume we have some UI that allows stakeholders to make updates to it. It could be a simple spreadsheet or a more robust interface:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    &amp;quot;blue&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;        &amp;quot;500&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;#006be6&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    &amp;quot;orange&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;        &amp;quot;500&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;#f97316&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since our components are already using this, we don’t need to change anything there. Sounds good! Except until the button needs to be orange. Since the button has &lt;code&gt;blue.500&lt;/code&gt; assigned, we’d need to go back into the button to change it to &lt;code&gt;orange.500&lt;/code&gt;. That’s not what we want because going back into the button’s code is a task for the engineer, and only the engineer. We need some way of having the decision to change from blue to orange for the button to be represented here.&lt;/p&gt;
&lt;p&gt;Why not have the system describe the element and property being affected? Something like &lt;code&gt;button.primary.bg&lt;/code&gt; and &lt;code&gt;button.primary.text&lt;/code&gt;. That way the person who is trying to update the color knows what it’ll affect, and the person assigning that variable knows where to place it. They don’t even need a design mockup to figure out where this goes. The place where it goes is right in the name. It makes it clear to everyone on the team what this thing is meant to represent. Let’s update our things:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    &amp;quot;button&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;        &amp;quot;primary&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;            &amp;quot;bg&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;#006be6&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;            &amp;quot;text&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;#fefefe&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This can be represented in some UI that makes it clear these are the colors for the primary button’s background and text so that a stakeholder can change it whenever they like. Now, the developer just needs to read from these new values:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-keyword)&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; Button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({ variant&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;props }) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;props} &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;            className&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{ &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;css&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;({ bg&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;button.primary.bg&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; }) } /&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What we’ve begun to introduce is called a “semantic” naming strategy. Using this, we describe what is going to be affected so that someone else can provide the value in the pipeline. This relieves the engineer from looking up or maintaining the presentation of the button and make it an exercise for folks that are more responsible for those decisions.&lt;/p&gt;
&lt;p&gt;Those visual regression tests? Now those tests happen before the list is published. We can know how the colors are meant to be used before they hit the components. We can check for contrast, create an alpha set for testing in real parts of the application. Separating the concerns balances the responsibility of the team.&lt;/p&gt;
&lt;h2 id=&quot;trust-the-process&quot;&gt;Trust the process&lt;/h2&gt;
&lt;p&gt;When a full-stack engineer first starts using a semantic naming strategy, they might be uncomfortable because the decision about what color the button is no longer belongs to them. It is delegated outside to another person. What if they choose the wrong color? Why does the button suddenly look weird? People are going to think it’s my fault and I did something wrong. These are all valid thoughts to have when encountering a new paradigm. New ways of approaching something that has been the same way over years is concerning.&lt;/p&gt;
&lt;p&gt;You must be thinking, why doesn’t Tailwind’s default approach lean on semantic naming? The answer is because the scenarios I’ve described above don’t happen often, but when they do the pain is felt. When you first put &lt;code&gt;bg-blue-500&lt;/code&gt; in your code, you don’t think about the future. Of course not, you are thinking about pushing this code right now. Changing this code is your future self’s problem. Tailwind isn’t preparing you for the future, it’s preparing you to ship right now and that’s often what matters. However, the reality is that without a semantic layer, it can’t easily account for iterations, experimentation, and stakeholder requests. Maybe you don’t have these, so you’ll never need to revisit the button.&lt;/p&gt;
&lt;p&gt;But when you do receive that ticket to change the button’s background color, the answer isn’t to dig back into the code. It’s to make sure the right person can make that decision without ever needing to ping you. That’s empowering your team to express their creativity while you get back to your own expertise.&lt;/p&gt;</content:encoded></item><item><title>Tiny toggle</title><link>https://blog.damato.design/posts/tiny-toggle</link><guid isPermaLink="true">https://blog.damato.design/posts/tiny-toggle</guid><pubDate>Tue, 05 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;Over at the &lt;a href=&quot;https://ds.house&quot;&gt;Design Systems House website&lt;/a&gt;, I made a small toggle for light and dark mode. While there’s an abundance of posts describing this, I didn’t find any that made it into a compact script of a few lines. Here’s how I did it, and some additional considerations to keep in mind.&lt;/p&gt;
&lt;h2 id=&quot;the-script&quot;&gt;The script&lt;/h2&gt;
&lt;p&gt;This is all the JavaScript that makes the toggle work:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; LOCALSTORAGE_KEY&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;dark&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; $toggle&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; document&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.getElementById&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;toggle&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;matches&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; window&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.matchMedia&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;(prefers-color-scheme: dark)&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; stored&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; window&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;localStorage&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.getItem&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;LOCALSTORAGE_KEY&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;$toggle&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.checked &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; stored &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;!==&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; ?&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; stored &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;#39;true&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; matches;&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:var(--astro-code-token-constant)&quot;&gt;$toggle&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;?.addEventListener&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;change&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (ev) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    window&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;localStorage&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.setItem&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;LOCALSTORAGE_KEY&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; String&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;ev&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;target&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;.checked));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This assumes that there is a &lt;code&gt;&amp;lt;input type=&amp;quot;checkbox&amp;quot; id=&amp;quot;toggle&amp;quot;&amp;gt;&lt;/code&gt; element in the HTML.
Let’s go over the lines:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We define a constant for the &lt;code&gt;localStorage&lt;/code&gt; key.&lt;/li&gt;
&lt;li&gt;We get the toggle element from the DOM.&lt;/li&gt;
&lt;li&gt;We check if the user has a preference for dark mode using &lt;code&gt;matchMedia&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We check if there’s a stored value in &lt;code&gt;localStorage&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;We set the toggle’s checked state based on the stored value or the user’s preference.&lt;/li&gt;
&lt;li&gt;We add an event listener to the toggle.&lt;/li&gt;
&lt;li&gt;When the toggle changes, we store the boolean value as a string in &lt;code&gt;localStorage&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Importantly, we assume that the initial presentation is “light” and explicitly look for if there’s any setting for “dark”. The first thing we look at is if it was set as “dark” for this site using the toggle from a previous session. If not, we check what the OS preference is. This is setting the initial state of the toggle element, being checked if “dark” is picked up from either of those conditions. Then we listen for changes to the toggle and only update the &lt;code&gt;localStorage&lt;/code&gt; value when the toggle is changed. This overrides the OS user preference when set.&lt;/p&gt;
&lt;h2 id=&quot;the-styles&quot;&gt;The styles&lt;/h2&gt;
&lt;p&gt;Now with the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Selectors/:has&quot;&gt;baseline &lt;code&gt;:has()&lt;/code&gt; selector&lt;/a&gt;, getting this to behave is pretty easy with a single selector to introduce a new expression:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-string-expression)&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;:has&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;#toggle:checked&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;    /* dark mode styles */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a very simple way to apply styles based on the state of the toggle. The &lt;code&gt;:has()&lt;/code&gt; selector allows us to check if the toggle is checked and apply styles accordingly. This way, we don’t need to add any additional classes or attributes to the body element to indicate the current mode. We can just rely on the state of the toggle itself.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;I’m deliberately avoiding the HTML of the toggle here. If you really want to know what the HTML is, you can grab it from &lt;a href=&quot;view-source:https://ds.house/&quot;&gt;the source over at ds.house&lt;/a&gt;. I think the JavaScript and CSS used are more important for this article.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;h2 id=&quot;about-system-settings&quot;&gt;About system settings&lt;/h2&gt;
&lt;p&gt;When I initially made this kind of toggle for light/dark, I thought about it differently. Instead of light/dark, I wanted to toggle between “system” and “opposite of system”. In other words, if the OS was set as “dark”, the toggle would then either align to what was set in the system or be the opposite when toggled. Visually in terms of presentation, there would be no difference. If your system was set to “dark”, then by default the site would be dark. If your system was “dark” and you wanted this site to be “light”, you would switch to the “opposite of system” option.&lt;/p&gt;
&lt;p&gt;This helps avoid the problem of setting a specific flag on the site once set. In the implementation above and at ds.house, once we store the state expected by the user for the website, there’s no way of resetting it back to the state of not being set. It’s either “light” or “dark” (or &lt;code&gt;false&lt;/code&gt;/&lt;code&gt;true&lt;/code&gt; in the code). With the “system” and “opposite of system” approach, you can always reset to “system” to align with the OS preference. In this way, setting &lt;code&gt;false&lt;/code&gt; is the same as not setting anything. This is a nice way to allow users to easily reset their preference without needing to clear &lt;code&gt;localStorage&lt;/code&gt; or have a separate “reset” button.&lt;/p&gt;
&lt;p&gt;There’s a few problems with this, one of them being that I could never figure out a good way to explain this setting. “System” as the default is fairly straightforward, but “opposite of system” is a bit more difficult to understand. The other problem is that it doesn’t really align with the mental model of how users think about light/dark mode. They think in terms of light and dark, not “system” and “opposite of system”. So I went with the more straightforward approach of just toggling between light and dark.&lt;/p&gt;
&lt;p&gt;If you’d rather use a &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt; instead of a &lt;code&gt;&amp;lt;input type=&amp;quot;checkbox&amp;quot;&amp;gt;&lt;/code&gt;, you can modify the script to accommodate that by referencing &lt;code&gt;.selected&lt;/code&gt; instead of &lt;code&gt;.checked&lt;/code&gt; in the appropriate places. Just make sure your HTML has matching values for &lt;code&gt;localStorage&lt;/code&gt; and the options in your &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt;. You might want this if you want to expose “system”, “light”, and “dark” as options.  &lt;a href=&quot;https://kilianvalkhof.com/2020/design/your-dark-mode-toggle-is-broken/&quot;&gt;Kilian Valkhof recommends&lt;/a&gt; having all three and &lt;a href=&quot;https://www.bram.us/2022/05/25/dark-mode-toggles-should-be-a-browser-feature/#the-problem-with-dark-mode-toggles&quot;&gt;Bramus Van Damme explains&lt;/a&gt; the different possible levels of setting this information.&lt;/p&gt;
&lt;h2 id=&quot;knowing-your-audience&quot;&gt;Knowing your audience&lt;/h2&gt;
&lt;p&gt;If you’re wondering why I opted to &lt;em&gt;not&lt;/em&gt; expose the “light”, “dark”, and “system” options at ds.house, it’s because no person is spending a signficant amount of time on that website. Enough that they’ll visit everyday to be productive. Setting whether or not “light” or “dark” is right for this person is most likely a one-time thing specifically for a single visit. It is unlikely that a user will want the presentation of this site to change over the course of a day, unlike productivity applications like email clients where you’ll visit multiple times a day. Those experiences will expect smarter customization options.&lt;/p&gt;
&lt;p&gt;For a small website that gets a visit every once in a while, keeping it simple might be the better approach. But it’s important to know the tradeoffs. And if you ever come up with a good word for “opposite of system”, do let me know.&lt;/p&gt;</content:encoded></item><item><title>Title goes here</title><link>https://blog.damato.design/posts/title-goes-here</link><guid isPermaLink="true">https://blog.damato.design/posts/title-goes-here</guid><pubDate>Wed, 20 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;Naming is &lt;a href=&quot;/posts/truly-semantic&quot;&gt;clearly something I think a lot about&lt;/a&gt;. So when I saw &lt;a href=&quot;https://twitter.com/nathanacurtis/status/1724500748388450587&quot;&gt;this tweet from Nathan Curtis&lt;/a&gt; about the way &lt;a href=&quot;https://twitter.com/shaunbent&quot;&gt;Shaun Bent&lt;/a&gt; and &lt;a href=&quot;https://spotify.design/&quot;&gt;his team at Spotify&lt;/a&gt; handle component composition has named slots, &lt;em&gt;I was triggered&lt;/em&gt;. Hot takes activate, here’s the image from the tweet:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/list-row-anatomy.jpeg&quot; alt=&quot;A component composition with named areas&quot;/&gt;&lt;/p&gt;
&lt;h2 id=&quot;pretweet&quot;&gt;Pretweet&lt;/h2&gt;
&lt;p&gt;There are several words in here that suggest position. For this exploration, I’ll focus on the title area, specifically the areas above and below the title slot. The team has chosen the words pretitle and subtitle for these areas, respectively. Seeing this, I went through the following stream of thought:&lt;/p&gt;
&lt;p&gt;Initially, I’d expect that the concepts should match. In other words, choose either pre/post or super/sub. There’s awkwardness in both choices. Choosing the former pair will result in a double-t (posttitle) while the latter pair will result in a suggested size of the title from the name (supertitle).&lt;/p&gt;
&lt;p&gt;I’ve recently adopted the concept of “overline” from &lt;a href=&quot;https://m2.material.io/design/typography/the-type-system.html#applying-the-type-scale&quot;&gt;Material Design&lt;/a&gt; for the area above headlines. While it might work using the word title (eg., “overtitle”, “undertitle”) it wouldn’t for other typographic terms as we may end up with a very confusing “underline”.&lt;/p&gt;
&lt;p&gt;Which is where I decided I couldn’t just reply to the tweet. I’m now conflicted about what I would name these areas so that they are clear to their purpose and relate to the title component appropriately. We need to go deeper.&lt;/p&gt;
&lt;h2 id=&quot;a-page-from-page-layout&quot;&gt;A Page from Page Layout&lt;/h2&gt;
&lt;p&gt;The parts we’re identifying here are from the anatomy of &lt;a href=&quot;https://en.wikipedia.org/wiki/Page_layout&quot;&gt;page layout&lt;/a&gt;; the arrangement of visual elements on a page. There’s a handful of parts that we should first address that could help us here:&lt;/p&gt;
&lt;h3 id=&quot;headline&quot;&gt;Headline&lt;/h3&gt;
&lt;p&gt;This is meant to be the most important element in the layout. As such, we expect this to have the largest font size and/or most ornate font style to capture the reader, along with its compelling content to continue traveling down the path it introduces.&lt;/p&gt;
&lt;h3 id=&quot;deck--kicker--intro--stand-first--lead--lede&quot;&gt;Deck / Kicker / Intro / Stand-first / Lead / Lede&lt;/h3&gt;
&lt;p&gt;This often summarizes the article and appears directly after the headline. It is meant to further engage the reader to move forward in the reading experience. In terms of treatment, we expect this to be smaller than the headline, but larger than the body copy. Due to the nature of there being multiple words to describe this idea; there are also many variations of expectation for this in terms of length and content.&lt;/p&gt;
&lt;h3 id=&quot;subhead&quot;&gt;Subhead&lt;/h3&gt;
&lt;p&gt;There’s some disagreement in the research I’ve done that identifies this element. In some examples, this is a synonym for &lt;a href=&quot;#deck--kicker--intro--stand-first--lead--lede&quot;&gt;deck&lt;/a&gt; but for others, it is specifically meant to break up large chunks of text.&lt;/p&gt;
&lt;h3 id=&quot;drop-cap&quot;&gt;Drop cap&lt;/h3&gt;
&lt;p&gt;This is often the first letter of a chunk of text but can sometimes be longer than this. It is stylized to be larger than the rest of the body copy it is associated with. We have ways of achieving this using &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements&quot;&gt;CSS pseudo elements&lt;/a&gt; such as &lt;code&gt;::first-letter&lt;/code&gt; and &lt;code&gt;::first-line&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;byline&quot;&gt;Byline&lt;/h3&gt;
&lt;p&gt;This is specifically the line of text that identifies who wrote the piece. It is used mostly for authors writing articles and begins with the word “by”.&lt;/p&gt;
&lt;h3 id=&quot;dateline&quot;&gt;Dateline&lt;/h3&gt;
&lt;p&gt;As you might expect, this is meant to present the date that the piece was reported however, &lt;a href=&quot;https://en.wikipedia.org/wiki/Dateline&quot;&gt;according to Wikipedia&lt;/a&gt;, it also describes where and when the story was written or filed, &lt;em&gt;though the date is often omitted&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id=&quot;caption&quot;&gt;Caption&lt;/h3&gt;
&lt;p&gt;This is text used to describe accompanying media such as images, photos, or illustrations. We will also see captions in media outside of page layout such as video in the form of closed captions. While we expect this text to be smaller than most body copy, it must be still legible. Importantly, captions are also subtitles that include a written description of other elements in the media.&lt;/p&gt;
&lt;h3 id=&quot;folio&quot;&gt;Folio&lt;/h3&gt;
&lt;p&gt;This is meant as metadata about the piece, often including the publisher’s name, page number, or year of publishing. This is often in the corners of printed pages in a smaller and less distracting typographic treatment.&lt;/p&gt;
&lt;h3 id=&quot;running-head&quot;&gt;Running head&lt;/h3&gt;
&lt;p&gt;This is meant to connect a story over multiple printed pages. On the web, this is less apparent as we have ways of allowing the headline to remain on an infinitely scrolling page.&lt;/p&gt;
&lt;h3 id=&quot;pull-quote--call-out--billboard&quot;&gt;Pull quote / Call out / Billboard&lt;/h3&gt;
&lt;p&gt;This is meant to highlight a particular topic or mention from the existing body copy. It is often displayed inline within the layout with a more engaging treatment, either by size or style.&lt;/p&gt;
&lt;h2 id=&quot;disambiguation&quot;&gt;Disambiguation&lt;/h2&gt;
&lt;p&gt;Many of these are often used interchangeably and have more meaning. For example, the difference between a headline and a title. From the &lt;a href=&quot;https://ell.stackexchange.com/a/201030&quot;&gt;English Language Learners Stack Exchange&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Headline” is normally used when an article appears as one of a collection of articles, such as a newspaper. If the article is reprinted separately, the headline becomes the “title”.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Another description of this difference is by the &lt;a href=&quot;https://thecontentauthority.com/blog/headline-vs-title&quot;&gt;Content Authority&lt;/a&gt;, providing this table of examples:&lt;/p&gt;





















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Headline&lt;/th&gt;&lt;th&gt;Title&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;How to Improve Your Writing Skills&lt;/td&gt;&lt;td&gt;10 Tips for Better Writing&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Why You Should Drink More Water&lt;/td&gt;&lt;td&gt;The Benefits of Staying Hydrated&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Breaking News: Earthquake Hits California&lt;/td&gt;&lt;td&gt;7.1 Magnitude Earthquake Rocks Southern California&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;In HTML web pages, the title is a metatag meant for the &lt;code&gt;&amp;lt;head/&amp;gt;&lt;/code&gt; of the webpage and is displayed outside of the content area of the webpage; either in the browser window or tab area. Meanwhile, the idea of a subtitle could be confused for the use within &lt;a href=&quot;#caption&quot;&gt;captions&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;purpose-not-position&quot;&gt;Purpose not position&lt;/h2&gt;
&lt;p&gt;You may have noticed that much of the descriptions above do not suggest the element’s position in the layout, but rather its purpose. This is the reason why the original tweet was so triggering for me. When we provide an API that is driven by placement, it allows different variations of lockups to emerge because the person supplying the content is less likely to truly understand &lt;em&gt;why&lt;/em&gt; they want this treatment. It becomes much harder to have a consistent presentation of these elements.&lt;/p&gt;
&lt;p&gt;That is why when we create a component like this, we should be preparing it by purpose. This will ensure that what the designer decides is done by intention. Where it is finally displayed is a separate layout exercise. As an example, in magazine layout, an article’s author does not have authority over the folio position. Less artistic articles may also have more restrictions on other elements such as the style of headline, deck, and body copy. This keeps the presentation consistent across the publication and readers become more familiar with the presentation; making it easier to read.&lt;/p&gt;
&lt;p&gt;Going back to the original example at the beginning of this article, I’d now recommend the following based on the above:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Headline slot&lt;/li&gt;
&lt;li&gt;Lead slot&lt;/li&gt;
&lt;li&gt;Media slot&lt;/li&gt;
&lt;li&gt;Caption slot&lt;/li&gt;
&lt;li&gt;Body slot&lt;/li&gt;
&lt;li&gt;Folio slot&lt;/li&gt;
&lt;li&gt;Callout slot&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I’ve omitted the leading and trailing areas specifically because the names do not suggest purpose, only position. In other words, &lt;strong&gt;what is supposed to appear in these spots?&lt;/strong&gt; If the answer is “anything you want”, that’s not systematic. One person could decide that the icon is meant to appear on the left while another expects that same icon on the right.&lt;/p&gt;
&lt;p&gt;As a practical example, the button component I’ve designed allows for an &lt;code&gt;icon&lt;/code&gt; prop which &lt;em&gt;only&lt;/em&gt; appears before the button’s label. The only way to have an icon appear after the label is for special purposes. For example, showing a caret when the button is meant to host a disclosure pattern.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Button&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; icon&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{ &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;Star&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;/&amp;gt; } &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;disclosure&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this API naming scheme, we can create several kinds of lockups. We could have a &lt;code&gt;&amp;lt;ListRow/&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;MediaCard/&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;Hero/&amp;gt;&lt;/code&gt;, or any other component which expects a hierarchy of content. We could also have different layout options specific to each once each of these is well-defined. Ones that allow the folio to appear above the headline as an example. The exercise of determining where each one of these elements goes should be separate from the exercise of curating the kinds of elements that need to appear and their content. In fact, designers often aren’t curating the content here. The decision about which kind of lockup to use might be the only decision required in some cases; such as widgets of a CMS.&lt;/p&gt;
&lt;p&gt;The opinion about where these elements should appear or how many variations exist should be influenced by the designers interested in these layouts but ultimately consolidated by design system governance to align on a common shared language by intention. Designers must articulate their needs past ego and identify how their choice is targeting a user’s need. That then informs this new API.&lt;/p&gt;
&lt;p&gt;Overall, I continue to recommend naming things with purpose.&lt;/p&gt;</content:encoded></item><item><title>Token operations</title><link>https://blog.damato.design/posts/token-operations</link><guid isPermaLink="true">https://blog.damato.design/posts/token-operations</guid><pubDate>Wed, 31 May 2023 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;I have been revisiting the infrastructure which supports themes at my day job where the number of tokens has exploded into the hundreds; thousands if you count the possibilities of defining custom ones for special needs. This makes the token curation process unwieldly when theming because assigning values to over 500 semantic tokens is very tedious.&lt;/p&gt;
&lt;p&gt;The trouble is that while a certain brand or theme might have a few base values which give it personality, the final collection of tokens to define a theme will require slight variations of these base values for a properly curated presentation.&lt;/p&gt;
&lt;p&gt;What if we could instead allow for a few values to be set in a theme to inform the rest of the values in some specified way?&lt;/p&gt;
&lt;h2 id=&quot;operations&quot;&gt;Operations&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/design-tokens/community-group/issues/88#issuecomment-1029905903&quot;&gt;First suggested within the Design Tokens Community Group by Jerome Farnum&lt;/a&gt; we could consider a special key on the specification that expects an order of operations to be performed (&lt;a href=&quot;https://github.com/design-tokens/community-group/issues/88#issuecomment-1073374383&quot;&gt;example from James Nash&lt;/a&gt;):&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  &amp;quot;some-token&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    &amp;quot;$value&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;#ff0000&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    &amp;quot;$type&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;color&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    &amp;quot;$operations&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;       { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;&amp;quot;hue&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; -20&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;       { &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;&amp;quot;alpha&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 0.3&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; } &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a good start but I saw two major flaws with this approach:&lt;/p&gt;
&lt;h3 id=&quot;freeform-naming&quot;&gt;Freeform naming&lt;/h3&gt;
&lt;p&gt;The words &lt;code&gt;hue&lt;/code&gt; and &lt;code&gt;alpha&lt;/code&gt; are meant to reference some external function that must exist in the token processing in order to transform to a final value. The algorithms used to determine the final output might be different or not exist at all. Each vendor must implement their own &lt;code&gt;hue&lt;/code&gt; and &lt;code&gt;alpha&lt;/code&gt; functions in order for these to be useful. This would require the specification to outline &lt;em&gt;every&lt;/em&gt; kind of possible transform a theme author might want to use.&lt;/p&gt;
&lt;h3 id=&quot;custom-functions&quot;&gt;Custom functions&lt;/h3&gt;
&lt;p&gt;Furthermore, theme curators could be interested in creating their own custom functions which would need to be executed in vendors’ processes. In this format, there’s no clear way to define this. We can’t even support multiple arguments in the current suggestion.&lt;/p&gt;
&lt;h2 id=&quot;step-by-step&quot;&gt;Step-by-step&lt;/h2&gt;
&lt;p&gt;The solution I have for this is to implement a low-level language that can be built upon to make more complex functions. Here’s an example of what a token file could look like with a new take on &lt;code&gt;$operations&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  &amp;quot;primary-color-overlay&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    &amp;quot;$type&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;color&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    &amp;quot;$value&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;#fffc00&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    &amp;quot;$operations&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;      0.5&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;String.match&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$value&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;#([0-9A-Fa-f]{2})&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;String.match&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$value&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;#(?:[0-9A-Fa-f]{2})([0-9A-Fa-f]{2})&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;String.match&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$value&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;#(?:[0-9A-Fa-f]{4})([0-9A-Fa-f]{2})&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;Math.parseInt&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 16&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;Math.parseInt&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$2&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 16&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;Math.parseInt&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$3&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 16&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;String.concat&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;,&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$4&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$5&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$6&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$0&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;String.concat&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;rgba(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$7&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;)&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://replit.com/@fauxserious/TokenOperations&quot;&gt;See minimal prototype in action.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;$operations&lt;/code&gt; key is still an array which is necessary to ensure we can have a sequential step. The first concept is that each item (except for the first in this example) is an &lt;strong&gt;operation&lt;/strong&gt;. It has the following signature:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;OperationReference&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;argument1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;argument2&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;argument3&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;...]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first item in each operation array references some well-known function that can be implemented across token processing tools and vendors. For this to work, I believe we’ll need at least &lt;code&gt;String&lt;/code&gt; and &lt;code&gt;Math&lt;/code&gt; with a few additional methods to support standard operations (eg., &lt;code&gt;Math.add&lt;/code&gt;). This is something that can be included in the tokens specification if agreeable.&lt;/p&gt;
&lt;p&gt;The result of each operation is stored in a special variable reference related to its index in the operations array. In the example above, the first operation (defined at index &lt;code&gt;1&lt;/code&gt;) result is stored at &lt;code&gt;&amp;quot;$1&amp;quot;&lt;/code&gt;. This result is used as an argument in the fifth operation (the first to use &lt;code&gt;Math.parseInt&lt;/code&gt; above).  Primitive values in the operations array are simply stored as results to the index. Here’s the example again, with comments marking how results are stored:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  &amp;quot;primary-color-overlay&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    &amp;quot;$type&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;color&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    &amp;quot;$value&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;#fffc00&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    &amp;quot;$operations&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;      0.5&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt; // 0.5 stored at $0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;String.match&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$value&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;#([0-9A-Fa-f]{2})&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt; // &amp;#39;ff&amp;#39; stored at $1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;String.match&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$value&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;#(?:[0-9A-Fa-f]{2})([0-9A-Fa-f]{2})&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt; // &amp;#39;fc&amp;#39; stored at $2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;String.match&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$value&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;#(?:[0-9A-Fa-f]{4})([0-9A-Fa-f]{2})&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt; // &amp;#39;00&amp;#39; stored at $3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;Math.parseInt&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 16&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt; // 255 stored at $4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;Math.parseInt&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$2&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 16&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt; // 252 stored at $5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;Math.parseInt&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$3&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 16&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt; // 0 stored at $6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;String.concat&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;,&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$4&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$5&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$6&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$0&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt; // 255,252,0,0.5 stored at $7&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;String.concat&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;rgba(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$7&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;)&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;// rgba(255,252,0,0.5) stored at $8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This would also include a special &lt;code&gt;$value&lt;/code&gt; which refers to the original token value.&lt;/p&gt;
&lt;p&gt;One of the larger benefits to this approach is that the low-level set of operations don’t receive a name, which avoids contention about naming of operations from within the specification (ie., should it be &lt;code&gt;opacity&lt;/code&gt; or &lt;code&gt;alpha&lt;/code&gt;). Names would only be needed when sharing sets of operations between token authors.&lt;/p&gt;
&lt;h2 id=&quot;reusing-common-operations&quot;&gt;Reusing common operations&lt;/h2&gt;
&lt;p&gt;Clearly, we would not want to write all of these operations in order to apply opacity to a given token each time. We’ll need a way to reference a set of operations. This could be supported by allowing an import syntax within the specification. &lt;a href=&quot;https://github.com/design-tokens/community-group/issues/210#issuecomment-1501037423&quot;&gt;I’ve suggested this idea before in the community group.&lt;/a&gt; It could look like this for operations:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  &amp;quot;primary-color-overlay&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    &amp;quot;$type&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;color&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    &amp;quot;$value&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;#fffc00&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    &amp;quot;$operations&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [ &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;      // All items after the import are used as arguments for the nested operation in order&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;      // 0.5 stored at $0 for @token-operations/hex-opacity operations&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;@token-operations/hex-opacity&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 0.5&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above example &lt;code&gt;@token-operations/hex-opacity&lt;/code&gt; is completely arbitrary and could be any package registry or url that has an array as the export. The expectation here is that folks might write projects that abstract low-level collections of operations into more user-friendly exports. This is similar to the purpose of the &lt;a href=&quot;https://lit.dev/&quot;&gt;Lit framework&lt;/a&gt; for component authoring; to make web component development more accessible with a level of abstraction.&lt;/p&gt;
&lt;p&gt;The special sauce would be within the operations parser. Since the first argument in an operation is meant to be a reference to a function (eg., &lt;code&gt;String.concat&lt;/code&gt;), we could also check for a potential file to import here or have some other special syntax. The result would be to inject the operations array related to this reference in place as a nested operation with its own scoped step indicies. The trailing arguments of the import are then placed in the beginning of the imported operation set since each curated operation has an expected signature.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  &amp;quot;primary-color-overlay&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    &amp;quot;$type&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;color&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    &amp;quot;$value&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;#fffc00&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    &amp;quot;$operations&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;      // First level of operations&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;        // Second level of operations (nested), final output returns to parent operation result in place&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        0.5&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt; // First argument after import operation, placed at $0 in nested operation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;String.match&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$value&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;#([0-9A-Fa-f]{2})&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;String.match&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$value&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;#(?:[0-9A-Fa-f]{2})([0-9A-Fa-f]{2})&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;String.match&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$value&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;#(?:[0-9A-Fa-f]{4})([0-9A-Fa-f]{2})&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;Math.parseInt&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 16&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;Math.parseInt&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$2&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 16&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;Math.parseInt&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$3&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 16&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;String.concat&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;,&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$4&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$5&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$6&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$0&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;        [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;String.concat&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;rgba(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;$7&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;)&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;      ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The purpose of this is so imported operations can be chained while maintaining the positional references for each step. In other words, we want to maintain the meaning of &lt;code&gt;$0&lt;/code&gt; related to the rest of the steps in place.&lt;/p&gt;
&lt;p&gt;In this way, as long as token processors include the low-level operational functions and the standardized way to execute them, you can define any kind of transform you need right within the token file.&lt;/p&gt;</content:encoded></item><item><title>Tokens as intents</title><link>https://blog.damato.design/posts/tokens-as-intents</link><guid isPermaLink="true">https://blog.damato.design/posts/tokens-as-intents</guid><pubDate>Thu, 12 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;There are tons of definitions of design tokens on the web. Enough that I won’t link to them here and you can find your favorite one with a web search. Many of the examples of design tokens show a relationship that looks something like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;color-blue-500&lt;/code&gt; ⬅ &lt;code&gt;#0000ff&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here, there’s a name that represents the value. The naming in this example indicates a few things like the category (color) then a family within the category (blue) and finally a way of showing a relation between similar tokens of the same depth (500). This was well advertised through the &lt;a href=&quot;https://material.io/design/color/the-color-system.html&quot;&gt;material design color palettes&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-immediate-problem&quot;&gt;The immediate problem&lt;/h2&gt;
&lt;p&gt;Now let’s say we design a button, and we want to give it an accent color from our palette. Maybe this is also our brand color and used for a few other marketing items as well.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.btn&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  background-color&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--color-blue-500)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  color&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--color-white)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Seems harmless. That is until you get a message from marketing and the brand colors are changing. What do you do? You might think a quick fix would be to do this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;color-blue-500&lt;/code&gt; ⬅ &lt;code&gt;orange&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Because &lt;code&gt;color-blue-500&lt;/code&gt; is the brand color, it’ll update in all of the spots. Clearly this isn’t a good approach because the name no longer matches the value.&lt;/p&gt;
&lt;p&gt;Instead you’d have to update all of the places where the brand color was used.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.btn&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  background-color&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--color-orange-500)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  color&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--color-white)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Oh wait, is that white accessible on the orange? That might need to be updated too!&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.btn&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  background-color&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--color-orange-500)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  color&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--color-black)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, you’d be combing through existing assets; looking for areas that need to be updated and never being sure you’ve gotten everything. We need a better system and you can probably give a recommendation already. Let’s change the mapping to the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;color-primary&lt;/code&gt; ⬅ &lt;code&gt;orange&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now, I can use that name without worrying about the value.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.btn&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  background-color&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--color-primary)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It doesn’t yet solve the relational colors (ie., the text color) but we’ll get there.&lt;/p&gt;
&lt;h2 id=&quot;provide-intention&quot;&gt;Provide intention&lt;/h2&gt;
&lt;p&gt;The concept that I’m describing is not new. It is a token naming approach that attempts to loosen the description of the value by providing more meaning. &lt;a href=&quot;https://twitter.com/nathanacurtis&quot;&gt;Nathan Curtis&lt;/a&gt; &lt;a href=&quot;https://medium.com/eightshapes-llc/naming-tokens-in-design-systems-9e86c7444676&quot;&gt;lands on this idea&lt;/a&gt; through an exploration of other systems’ naming conventions without explicitly calling them more than design tokens.&lt;/p&gt;
&lt;p&gt;What Nathan calls &lt;em&gt;concepts&lt;/em&gt; in his post is the basis behind the naming convention that I’ve been calling &lt;em&gt;intents&lt;/em&gt; since 2017 which is a term coined by &lt;a href=&quot;https://twitter.com/josephschmitt&quot;&gt;Joe Schmitt&lt;/a&gt;. The idea is that &lt;strong&gt;the token name should describe an intention, not the value&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;As a designer, I want to place a button inside of a card. What kind of button should go into that card? I don’t mean what color or font size, I mean &lt;em&gt;what kind of button&lt;/em&gt;. When we design an interface we are making decisions about the kind of thing to use that is expected to help the user move forward. We decide to use a primary button because we want to draw the user’s attention here first before any other action. The kind of button is primary due to its priority and the decision I’m making is an &lt;strong&gt;intent&lt;/strong&gt;. We can separate the intent from the styles we associate with that intent.&lt;/p&gt;
&lt;p&gt;Another example would be an alert banner. Which banner should I use to show your credit card is about to expire? I’m not looking for the orange banner, I’m looking for the warning banner. I intend to describe to the user that this message is a warning. If you think in this way, the style of the warning is not important. It’s the decision about how we expect to convey this message that is important.&lt;/p&gt;
&lt;p&gt;If you fully adopt this approach, this helps by teaching the user similarly styled things have the same behavior. It’ll be easy for a user to identify all primary actions or warning statuses because they have the same treatment (or have the same intent) across uses.&lt;/p&gt;
&lt;p&gt;To be clear &lt;strong&gt;intents are tokens&lt;/strong&gt;. They just have a special purpose in the ecosystem.&lt;/p&gt;
&lt;h2 id=&quot;a-new-system-of-naming&quot;&gt;A new system of naming&lt;/h2&gt;
&lt;p&gt;If we use the intent based naming system, the mapping might have an assignment like these:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;feedback-warning-surface-color&lt;/code&gt; ⬅ &lt;code&gt;color-orange-500&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;feedback-warning-onsurface-color&lt;/code&gt; ⬅ &lt;code&gt;#fff&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Notice that the right-hand side can be a raw value or some other variable. It might help for these to be reusable variables like &lt;code&gt;color-orange-500&lt;/code&gt; because you might reuse this value is other places. What matters is that the intent name (the left-hand side) does not change.&lt;/p&gt;
&lt;p&gt;Those intent names are describing parts of the experience where we intend to show a warning by using a background color and a foreground color. When you set an intent as a component property value, this is effectively a marriage. It should never change.&lt;/p&gt;
&lt;p&gt;Now we can use the &lt;code&gt;feedback-warning-surface-color&lt;/code&gt; in places of the experience where we intend to show a warning. These areas will not change their intent! We will always show a warning here, even if we style it differently later.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.alert-warning&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  background-color&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--feedback-warning-surface-color)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  color&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--feedback-warning-onsurface-color)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this system, you are able to support any variation of theming; light &amp;amp; dark mode, brand changes, private labeling, etc.. All you need to do is store different mappings of values to intents (aka. &lt;em&gt;theme&lt;/em&gt;). Maybe in one theme, warnings need to be shown in red. In that theme change the mapping for warning backgrounds to red.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;feedback-warning-surface-color&lt;/code&gt; ⬅ &lt;code&gt;color-red-300&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You’ll never need to go into the components to make a change as long as we use intents to describe the styles. Just make a new theme and give the experience a new look.&lt;/p&gt;
&lt;h2 id=&quot;recommendations&quot;&gt;Recommendations&lt;/h2&gt;
&lt;p&gt;I’ve have a few years of experience with this approach and want to document some of the pitfalls to avoid when implementing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Avoid the words light and dark&lt;/strong&gt;. You might consider trying this for buttons that appear on inverted backgrounds. Instead, I recommend setting an inverted theme within that container so it can cover all of the possible treatments within. Remember, it’s probably not just the button that needs to be inverted, there’s probably text or input fields that might need coverage too. If you really need to show a relationship use the word “contrast” instead.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Make naming relative to the page styles&lt;/strong&gt;. I recommend a very generic category called “box” which in its simplest form describes the &lt;code&gt;&amp;lt;body/&amp;gt;&lt;/code&gt; styles.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;box-background-color&lt;/code&gt;: The &lt;code&gt;&amp;lt;body/&amp;gt;&lt;/code&gt; background color.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;box-foreground-color&lt;/code&gt;: The &lt;code&gt;&amp;lt;body/&amp;gt;&lt;/code&gt; text / icon color related to the background.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;box-border-color&lt;/code&gt;: The most common border color for boxes which will share the &lt;code&gt;&amp;lt;body/&amp;gt;&lt;/code&gt; background color.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In my experience there might be another kind of container that is meant to show a visual difference from the body background. I tend to name this &lt;code&gt;boxLowContrast&lt;/code&gt; because it is still relational to the &lt;code&gt;&amp;lt;body/&amp;gt;&lt;/code&gt;. If you have more variations that this, you’ll have to get creative with your naming here. Remember, this is for generic non-interactive containers. You can have additional categories for more meaningful containers.&lt;/p&gt;
&lt;p&gt;Doing this allows you to keep in the mindset of a theme when completing the mapping.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;// &amp;quot;light theme&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  &amp;quot;box-background-color&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;#fff&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt; // white&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  &amp;quot;box-foreground-color&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;#000&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt; // black&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;// &amp;quot;dark theme&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  &amp;quot;box-background-color&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;#000&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt; // black&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  &amp;quot;box-foreground-color&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;#fff&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt; // white&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Start with generic categories&lt;/strong&gt;. A component is not necessarily an intent. You can consider a tab to be a part of an actionable category. Perhaps dive a step deeper into a navigational category. However, I would not recommend making a “tab” category.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;action-background-color&lt;/code&gt;: Generic, describes all interactive element backgrounds.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;navigation-background-color&lt;/code&gt;: More specific, describes all interactive element backgrounds which are meant for navigation.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tab-background-color&lt;/code&gt;: Very specific, only describes the tab background color.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here are some categories that have worked well in the past:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;box&lt;/strong&gt;: Describes generic non-interactive containers, eg. &lt;code&gt;&amp;lt;body/&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;action&lt;/strong&gt;: Describes interactive containers, eg. &lt;code&gt;&amp;lt;button/&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;navigation&lt;/strong&gt;: Describes interactive containers for the purpose of navigation, eg. &lt;code&gt;&amp;lt;a/&amp;gt;&lt;/code&gt; (link).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;control&lt;/strong&gt;: Describes interactive containers for the purpose of inputting information, eg. &lt;code&gt;&amp;lt;input/&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;feedback&lt;/strong&gt;: Describes non-interactive containers for the purpose of indicating a system state to the user, eg. banners, badges, notifications.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;figure&lt;/strong&gt;: Describes the use of color meant to segregate entities, eg. data-visualizations, illustrations, default avatar colors.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;text&lt;/strong&gt;: Describes all use of typography, more on this later.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The feedback and figure colors are unlike the others. For the feedback category I recommend the following set of properties.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;feedback-[type]-surface-color&lt;/code&gt;: Describes when the background is used to indicate the status through color. This is meant for banners that use the background as the color accent.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;feedback-[type]-onsurface-color&lt;/code&gt;: Describes the color to use for elements that appear on the &lt;code&gt;feedback-[type]-surface-color&lt;/code&gt; such as text and icons.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;feedback-[type]-foreground-color&lt;/code&gt;: Describes when the text is used to indicate the status through color. An example of this might be error text underneath an input field. This color is related to the &lt;code&gt;box-background-color&lt;/code&gt; in terms of contrast and application.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A caveat here is that if you attempt to put more complicated experiences within a container which has &lt;code&gt;feedback-[type]-surface-color&lt;/code&gt;, the related &lt;code&gt;feedback-[type]-onsurface-color&lt;/code&gt; will have difficulty applying coverage to the elements within. The recommendation here is to keep the feedback to text and icons only.&lt;/p&gt;
&lt;p&gt;The figure category is the least well understood. The best way to curate this is to order the colors by expected popularity within coloring illustrations. This is also a good area to consider having more specific categories if necessary. For example, if the colors used for illustrations are different from those being used within data-visualizations. Otherwise I just number these to indicate popularity.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;figure-color-1&lt;/code&gt;: The most used color within illustrations (other than box colors).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;figure-color-2&lt;/code&gt;: The next most used color within illustrations.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;figure-color-3&lt;/code&gt;: …and so on.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I’ve avoided trying to describe intents for the purposes of marketing because decisions of color there are often based on associated with given photography. In these areas you might opt to actual hard code the color because of the close association with the surrounding material and not necessarily with the overall page. Another recommendation might be to just have the following intents to only be used in places where the brand should be highlighted and not for areas with better intents.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;feedback-brand-surface-color&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;feedback-brand-onsurface-color&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;feedback-brand-foreground-color&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Create additional variations to each category&lt;/strong&gt; as necessary or potentially extend variations to others. For example we can imagine that all interactive categories will require a “hover” variation. Which would mean the following intents may exist:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;actionHovered-foreground-color&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;navigationHovered-foreground-color&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;controlHovered-foreground-color&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember to cover all of the possible states that your interaction might have.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;I’ve chosen to use the past tense to describe these states to indicate what has happened. You can think about this with the word “selected” where we wouldn’t use the word “select” to describe the state. You can also think of the word you might use if combined with “is” (ie., is hovered, is focused).&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;One more note, if you are using focus rings, I recommend associating the ring with the &lt;em&gt;box&lt;/em&gt; category because the ring visually appears on the box, not on the interactive element. As you might expect, having the same focus treatment across all interactive elements will be best and having it associated with the box category makes this easy to maintain. This would also go for shadows, although shadows have much more to do with light cast rather than a theme and could be avoided altogether.&lt;/p&gt;
&lt;h2 id=&quot;typography&quot;&gt;Typography&lt;/h2&gt;
&lt;p&gt;I’ve mentioned in the recommendation that there should be an entire intent category dedicated to text. This is meant to have the same approach where each kind of text is identified based on purpose. Here are the variations that seem to work best.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Heading&lt;/strong&gt;: Meant for large titles.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Title&lt;/strong&gt;: Meant for small titles.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Action&lt;/strong&gt;: Meant for text within interactive elements.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Input&lt;/strong&gt;: Meant for text within text fields.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Caption&lt;/strong&gt;: Meant for text providing additional detail, like help &amp;amp; error messages.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This isn’t including the default category. So you’d see the following in a theme:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;// default theme&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  &amp;quot;text-font-weight&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 400&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt; // body font weight&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  &amp;quot;textHeading-font-weight&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 700&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  &amp;quot;textTitle-font-weight&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 600&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Clearly, this method doesn’t support different levels of content hierarchy with just this collection of tokens alone. To do that you could either base the type scale on density (as is done here in the &lt;a href=&quot;https://damato.design&quot;&gt;damato.design&lt;/a&gt; family of sites.) or use the given font size as a base to compute additional font sizes using a set scale. That’s an explanation for another post.&lt;/p&gt;
&lt;h2 id=&quot;and-beyond&quot;&gt;And beyond&lt;/h2&gt;
&lt;p&gt;From here you can include additional properties to each category or even add categories as your organization needs. Here within the &lt;a href=&quot;https://system.damato.design&quot;&gt;damato.design system&lt;/a&gt; we have identified &lt;code&gt;border-size&lt;/code&gt;, &lt;code&gt;border-curve&lt;/code&gt;, and &lt;code&gt;density-size&lt;/code&gt; as additions to the box category to describe those features.&lt;/p&gt;</content:encoded></item><item><title>Truly Semantic</title><link>https://blog.damato.design/posts/truly-semantic</link><guid isPermaLink="true">https://blog.damato.design/posts/truly-semantic</guid><pubDate>Tue, 07 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;Off the heels of &lt;a href=&quot;https://www.clarityconf.com/session/mise-en-mode&quot;&gt;my talk at Clarity this year&lt;/a&gt; I omitted a few concepts that could have been included but may have detracted from the focus of the talk. One of these was the qualities that make a token truly semantic. I’ve had many arguments in the community regarding tokens that are or are not semantic. So the purpose of this article is to be clear about which tokens are best used directly in the experience from other tokens that can be used for organizational purposes.&lt;/p&gt;
&lt;h2 id=&quot;semantic-tokens-do-not-suggest-values&quot;&gt;Semantic tokens do not suggest values&lt;/h2&gt;
&lt;p&gt;This is an image from the Mise en Mode talk, which begins to introduce why space is not semantic in most systems.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/non-semantic-tokens.png&quot; alt=&quot;button-bgcolor is meant for buttons, space-4 cannot be placed&quot;/&gt;&lt;/p&gt;
&lt;p&gt;The semantic token &lt;code&gt;button-bgcolor&lt;/code&gt; does not give any indication of the color that is meant for this token. While a token &lt;code&gt;color-blue-500&lt;/code&gt; suggests that the color meant for this token is a blue, perhaps in the middle of other blues within a scale. This is an important distinction because we want the ability for these tokens to change based on outside factors; a common example being light mode and dark mode. However, we are not just limited to these user preferences. The color can change based on branding, localization, or expressiveness. It would be inappropriate to change the value of &lt;code&gt;color-blue-500&lt;/code&gt; to an orange, which is why we instead use and change &lt;code&gt;button-bgcolor&lt;/code&gt; because it does not suggest the value.&lt;/p&gt;
&lt;p&gt;I suggest that we ultimately do not need tokens that aren’t semantic functionally in our ecosystems. However, the reason why a token like &lt;code&gt;color-blue-500&lt;/code&gt; exists seems to be for human discourse. It is easier for people to speak about a color in a human-readable way than a color code. It also restricts the number of possible colors to use so slight variations of the same value do not appear accidentally.&lt;/p&gt;
&lt;h2 id=&quot;semantic-tokens-are-generic-component-tokens&quot;&gt;Semantic tokens are generic component tokens&lt;/h2&gt;
&lt;p&gt;This was one of the images that didn’t make it into the Mise en Mode talk:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/scooby-tokens.png&quot; alt=&quot;Fred from Scooby Doo, unmasking semantic tokens to reveal component tokens&quot;/&gt;&lt;/p&gt;
&lt;p&gt;When you are in the process of identifying what semantic tokens to include, you should aim to keep the number of tokens low. This helps with token management but also ensures that ideas are consistent across the experience. As an example, I believe that items that you can click should be given similar treatments so a user learns these are the clickable areas. If we were to provide different treatments to these components, the user may miss options because the treatment is unique.&lt;/p&gt;
&lt;p&gt;In this way, I like to create categories of components. For example, all components where we expect a user to provide input to the system could be called “control” components which would suggest a family of tokens that are meant to style controls similarly. From here, we would get semantic tokens such as &lt;code&gt;control-borderColor&lt;/code&gt; which might describe the &lt;code&gt;&amp;lt;input/&amp;gt;&lt;/code&gt; border.&lt;/p&gt;
&lt;p&gt;While you could become more specific, this tends to cause treatments to be more unique. As an example, would you expect &lt;code&gt;textInput-borderColor&lt;/code&gt; to be different from &lt;code&gt;checkbox-borderColor&lt;/code&gt;? Probably not. So the exercise of identifying similar atomic components is important to determining your semantic token set. These similar components are grouped into generic categories (eg., non-interactive surfaces, actions, controls, etc.) which form the foundation for your tokens.&lt;/p&gt;
&lt;p&gt;A good exercise to determine what your semantic tokens could be is by reviewing low-fidelity wireframes of your experience. Because these are meant to describe the pure functionality of the experience, without any additional noise of possible expressions, we can identify the most critical parts of the experience. Then we put those elements into categories based on their purpose in the experience. That purpose is the intention; the semantic meaning for why they exist here.&lt;/p&gt;
&lt;h2 id=&quot;semantic-tokens-are-not-dependent-on-each-other&quot;&gt;Semantic tokens are not dependent on each other&lt;/h2&gt;
&lt;p&gt;This is the “smedium” problem. A semantic token can be added or removed from the ecosystem without having to rethink other tokens within the same category. On the other hand, if you have a token called &lt;code&gt;space-sm&lt;/code&gt; and another called &lt;code&gt;space-md&lt;/code&gt;, you’ll be unable to introduce another token between them without introducing something unexpected and not systematic. So a good rule of thumb is that semantic tokens do not include a scale. The scale suggests that there are other tokens above and below that could require tokens to be inserted between these over time.&lt;/p&gt;
&lt;p&gt;A caveat is the ordinal system (primary, secondary, etc) which is meant to suggest priority and hierarchy within the experience, which should not change between token values. As an example, the primary button is the action that we expect the user should take in relation to all other actions on the page. This is regardless of the treatment provided to the button. The primary action should also be apparent in low-fidelity wireframes. Because of this, a specialized purpose of hierarchy within the experience regardless of expression, the token &lt;code&gt;buttonPrimary-bgcolor&lt;/code&gt; is appropriate. In contrast, the token &lt;code&gt;space-md&lt;/code&gt; cannot be given a purpose in the same way. We cannot accurately determine what a &lt;code&gt;space-md&lt;/code&gt; would be in a low-fidelity wireframe nor does it truly matter to the end-user to achieve their goals.&lt;/p&gt;
&lt;h2 id=&quot;what-can-be-semantic&quot;&gt;What can be semantic?&lt;/h2&gt;
&lt;p&gt;Color and typography can be described as semantic tokens. &lt;a href=&quot;https://complementary.space/&quot;&gt;Space can also be semantic&lt;/a&gt; if you reprogram the way you think about space. What semantic tokens have in common is that they have a simple, yet consistent, construction:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[purpose]-[priority]-[property]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Priority is optional and introduced if the content described must have an order of importance for the user. Describing space in importance is not necessary. Also, I am omitting interactive alternatives like hover and chosen for simplicity but they may also be included in the construction.&lt;/p&gt;
&lt;p&gt;This would suggest that elevation can also be semantic as we use this to describe importance; elements closer to the user should be perceived as more important. So we’d expect tokens such as &lt;code&gt;surface-primary-shadow&lt;/code&gt;. Notice that we aren’t introducing &lt;code&gt;surface-highest-shadow&lt;/code&gt; as we aren’t attempting to suggest how it looks but again the purpose. &lt;code&gt;modal-shadow&lt;/code&gt; could also be appropriately semantic; only a more specific semantic token better known as a component token.&lt;/p&gt;
&lt;p&gt;Using the ordinal system helps out in other ways. It ensures that an element is not introduced that attempts to represent “more-than-primary” (something many marketers would love to try). It also suggests that priorities lower than tertiary are cumbersome and therefore avoided. I’d also include that having more than 3 levels is useless for user interpretation within the experience in the same way we often omit heading levels less than &lt;code&gt;h3&lt;/code&gt; from most experiences.&lt;/p&gt;
&lt;h2 id=&quot;expanding-outside-of-tokens&quot;&gt;Expanding outside of tokens&lt;/h2&gt;
&lt;p&gt;In the exploration of &lt;a href=&quot;https://mode.place&quot;&gt;Mise en Mode&lt;/a&gt;, I also considered suggesting a naming convention for modes. However, I quickly realized that this too required additional context. I mentioned at the end of &lt;a href=&quot;/posts/ondark-virus&quot;&gt;Ondark Virus&lt;/a&gt; that we should consider semantic naming at the scope level. This suggests that the words “light” and “dark” are also inappropriate and considers a possibility where the curation of values is for a semantic purpose. In other words, &lt;em&gt;why&lt;/em&gt; do we need this new collection of values? What are we trying to express?&lt;/p&gt;
&lt;p&gt;The result of this question should be a research study to uncover why people are asking for “dark mode” because perhaps they are really asking for improved battery performance when browsing or perhaps more contrast for readability. In this way, we encode the purpose for the new collection of values as a semantically named mode which allows the purpose to be understood.&lt;/p&gt;
&lt;p&gt;Importantly, I do not suggest that the words “light” and “dark” be reimagined for user preference. I do not believe that users truly understand &lt;em&gt;why&lt;/em&gt; they select light or dark without introspective questions or explicit instruction; it often becomes a matter of unconscious preference. However, I believe it is our responsibility in design to understand our users’ needs better than they do so that we provide solutions they didn’t fully realize. In this way, I would recommend renaming “dark mode” internally to align with its semantic purpose, while continuing to expose “dark mode” as a user preference externally. From here, determine why the user selects a mode and provide the appropriate values to reflect this choice based on understood user needs. I will admit, that some users will simply suggest that a mode looks better, but this might be an indication of stylistic preference and suggest they would rather have the ability to customize their experience.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#naming-is-hard&lt;/strong&gt; because understanding why is hard.&lt;/p&gt;</content:encoded></item><item><title>Two Typographic Tricks</title><link>https://blog.damato.design/posts/two-typographic-tricks</link><guid isPermaLink="true">https://blog.damato.design/posts/two-typographic-tricks</guid><pubDate>Thu, 19 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;I’ve been writing CSS for a long time and it’s really exciting to see the fast improvements to the language that we’ve received over that time. In this post, I’ll demonstrate two ideas that I always wanted to do natively with CSS alone.&lt;/p&gt;
&lt;p&gt;First, a warm-up before we get to the wild stuff.&lt;/p&gt;
&lt;h2 id=&quot;grid-centered-line-height&quot;&gt;Grid centered line-height&lt;/h2&gt;
&lt;p&gt;I know of plenty of designers who want to maintain a &lt;a href=&quot;https://zellwk.com/blog/why-vertical-rhythms/&quot;&gt;vertical rhythm&lt;/a&gt; for all content on the page. They’ll painstakingly adjust border widths and line-heights to ensure all of the little elements on the page align to some vertical grid such that there’s a rhythm to reading downward.&lt;/p&gt;
&lt;p&gt;As the person who wrote &lt;a href=&quot;https://gridless.design/&quot;&gt;Gridless Design&lt;/a&gt;, you can imagine how I feel about this. In my opinion, the time spent trying to get this alignment would be more worthwhile on other things; say… improving the user experience as an example. However, now that we have some new CSS in browsers, getting the vertical rhythm to align with your grid can happen at any font size very easily.&lt;/p&gt;
&lt;p&gt;We’re going to need a bit of math for this. Let’s say that you have an &lt;a href=&quot;https://notadesigner.io/p/8px-grid&quot;&gt;&lt;code&gt;8px&lt;/code&gt; grid&lt;/a&gt;. This means elements on your composition should be sized in multiples of &lt;code&gt;8px&lt;/code&gt;. Let’s also say that your &lt;code&gt;line-height&lt;/code&gt; for paragraphs should be &lt;code&gt;1.4&lt;/code&gt;, meaning the resulting height of each line should be 1.4 times the size of the font so the space between lines helps readability. If your paragraph font is &lt;code&gt;18px&lt;/code&gt;, this means the paragraph &lt;code&gt;line-height&lt;/code&gt; would result in each line of text being &lt;code&gt;25.2px&lt;/code&gt; high.&lt;/p&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.css&quot; integrity=&quot;sha384-WsHMgfkABRyG494OmuiNmkAOk8nhO1qE+Y6wns6v+EoNoTNxrWxYpl5ZYWFOLPCM&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;18&lt;/mn&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mn&gt;1.4&lt;/mn&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;25.2&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;18*1.4=25.2&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;18&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1.4&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;25.2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Clearly, this doesn’t align to our &lt;code&gt;8px&lt;/code&gt; grid. Historically, we’d curate the &lt;code&gt;line-height&lt;/code&gt; each time we introduce a new &lt;code&gt;font-size&lt;/code&gt;. In this case, we have to hardcode the &lt;code&gt;line-height&lt;/code&gt; knowing the &lt;code&gt;font-size&lt;/code&gt; such that it remains on the &lt;code&gt;8px&lt;/code&gt; grid.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.paragraph&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    font-size&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 18&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    line-height&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--paragraph-lineheight)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;rounding-to-the-nearest-grid&quot;&gt;Rounding to the nearest grid&lt;/h3&gt;
&lt;p&gt;In order to determine the correct number here, we’ll need to round 25.2 to the nearest 8. Doing this in JavaScript would look like this, assuming the numbers are entered without units:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; lineHeight&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(fontSize &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 18&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; lhTarget &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1.4&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; gridUnit &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; Math&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.ceil&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;((fontSize &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; lhTarget) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; gridUnit) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; gridUnit;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The messy part is rounding to the nearest grid unit. We have to divide 25.2 by 8, then round that to the nearest integer and then multiply by 8 to get 32. This means that the &lt;code&gt;--paragraph-lineheight&lt;/code&gt; should be set as &lt;code&gt;32px&lt;/code&gt; when the font size is &lt;code&gt;18px&lt;/code&gt; and the target line height is &lt;code&gt;1.4&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As you can see, this is very cumbersome. We’d need to know the exact &lt;code&gt;font-size&lt;/code&gt; value, the grid unit, and the target &lt;code&gt;line-height&lt;/code&gt; for this kind of element to determine the final result.&lt;/p&gt;
&lt;p&gt;Luckily, the new &lt;code&gt;round()&lt;/code&gt; CSS function can really help us out.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.paragraph&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    line-height&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; round(up&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1.4&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;em&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--grid-unit&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is effectively the same calculation that was demonstrated earlier in JavaScript. The &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/round&quot;&gt;&lt;code&gt;round()&lt;/code&gt; function&lt;/a&gt; is &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/round#browser_compatibility&quot;&gt;fairly well supported&lt;/a&gt; and can take three arguments:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The first can determine the rounding strategy, in this case we want to round up in the same way we used &lt;code&gt;Math.ceil()&lt;/code&gt; before.&lt;/li&gt;
&lt;li&gt;The next argument is the number we’re going to be rounding. This will represent the target &lt;code&gt;line-height&lt;/code&gt;; basically the minimum &lt;code&gt;line-height&lt;/code&gt; allowed. Unfortunately, we can’t use the unitless &lt;code&gt;line-height&lt;/code&gt; here but we can use the &lt;code&gt;em&lt;/code&gt; version instead which would result in the same final pixel amount.&lt;/li&gt;
&lt;li&gt;Finally, the amount to round by. This part of the function is &lt;strong&gt;awesome&lt;/strong&gt;. It avoids all of the weird division and multiplication to round by an amount in the JavaScript. Here, we want to round to the nearest grid unit. In this example, I simply set the default as &lt;code&gt;8px&lt;/code&gt; in the second argument of the &lt;code&gt;var()&lt;/code&gt;, and then it can accept any update in the page and fallback to &lt;code&gt;8px&lt;/code&gt;. You can also use any value with units here instead.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You’ll also notice I’m not explicitly setting the &lt;code&gt;font-size&lt;/code&gt; here. This is because this &lt;code&gt;line-height&lt;/code&gt; value will respect whatever &lt;code&gt;font-size&lt;/code&gt; this element is because it’s referencing &lt;code&gt;em&lt;/code&gt; units, even if it is inherited from a parent! If your target &lt;code&gt;line-height&lt;/code&gt; is meant to be tighter, as is normally the case for headings, you can adjust the target to be smaller like &lt;code&gt;1.2em&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.heading&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    line-height&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; round(up&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1.2&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;em&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--grid-unit&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here is a codepen demonstrating the technique. The gray lines behind the text represent the grid unit intervals and the red background on the text shows how much space the text takes up. You’ll see that the gray lines will never be cut-off at the bottom of the container because the &lt;code&gt;line-height&lt;/code&gt; for this element is &lt;em&gt;always&lt;/em&gt; on grid. The span is not important to the CSS, it’s there just to visualize the height of the text.&lt;/p&gt;
&lt;iframe height=&quot;500&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;Line Height on grid&quot; src=&quot;https://codepen.io/fauxserious/embed/wBwdwNa?default-tab=css%2Cresult&quot; frameborder=&quot;no&quot; loading=&quot;lazy&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/fauxserious/pen/wBwdwNa&quot;&gt;
Line Height on grid&lt;/a&gt; by Donnie D’Amato (&lt;a href=&quot;https://codepen.io/fauxserious&quot;&gt;@fauxserious&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;Ok, that was a good warm-up. Now it’s time to get wild!&lt;/p&gt;
&lt;h2 id=&quot;dynamic-letter-spacing&quot;&gt;Dynamic letter-spacing&lt;/h2&gt;
&lt;p&gt;Like &lt;code&gt;line-height&lt;/code&gt;, I always felt that tweaking the &lt;code&gt;letter-spacing&lt;/code&gt; was a waste of time. Especially as more custom fonts become normal, I felt setting the &lt;code&gt;letter-spacing&lt;/code&gt; should be embedded in the font file itself. However, I saw &lt;a href=&quot;https://www.linkedin.com/posts/badimon_theres-this-strange-perception-effect-where-activity-7267563944435757056-BhJv/#&quot;&gt;a post by Mathieu Badimon&lt;/a&gt;, formerly leading efforts for the design system at Adobe, sharing a way to do this &lt;em&gt;dynamically&lt;/em&gt;. The gist is that he’s developed a scale where the &lt;code&gt;letter-spacing&lt;/code&gt; of the text will get tighter as the &lt;code&gt;font-size&lt;/code&gt; increases. Immediately, I wanted to try to do this in CSS alone. This took much longer than I hoped.&lt;/p&gt;
&lt;h3 id=&quot;the-easy-parts&quot;&gt;The easy parts&lt;/h3&gt;
&lt;p&gt;The first thing is that there is an upper and lower limit. This is pretty easy in CSS today using the &lt;code&gt;clamp()&lt;/code&gt; function. So we’ll start with that using the values he recommends in the post; Sizes &lt;code&gt;25px&lt;/code&gt; and below should be &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;-4%&lt;/code&gt; for sizes above about &lt;code&gt;145px&lt;/code&gt;. Since, &lt;code&gt;letter-spacing&lt;/code&gt; doesn’t accept &lt;code&gt;%&lt;/code&gt; units, we’ll use &lt;code&gt;em&lt;/code&gt; instead which can be thought of as a percent of the &lt;code&gt;font-size&lt;/code&gt;. Remember that the lowest value goes first, that’s why &lt;code&gt;-0.04em&lt;/code&gt; is first and &lt;code&gt;0em&lt;/code&gt; is last.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.paragraph&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    letter-spacing&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; clamp&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        -0.04&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;em&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--ems) * 1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;em&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;em&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    )&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ok, so far so good. Now all we need is the rate of change. You’ll see that there’s a graph included in his post, but he mentions that the graph is actually inaccurate. That’s fine, we’re going to use the numbers &lt;a href=&quot;https://www.linkedin.com/feed/update/urn:li:ugcPost:7267563941390684160?commentUrn=urn%3Ali%3Acomment%3A%28ugcPost%3A7267563941390684160%2C7268482417206689792%29&amp;replyUrn=urn%3Ali%3Acomment%3A%28ugcPost%3A7267563941390684160%2C7268561421481738240%29&amp;dashCommentUrn=urn%3Ali%3Afsd_comment%3A%287268482417206689792%2Curn%3Ali%3AugcPost%3A7267563941390684160%29&amp;dashReplyUrn=urn%3Ali%3Afsd_comment%3A%287268561421481738240%2Curn%3Ali%3AugcPost%3A7267563941390684160%29&quot;&gt;he provided later in a comment&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/dynamic-letter-spacing-chart.png&quot; alt=&quot;Dynamic Letter Spacing Chart&quot;/&gt;&lt;/p&gt;
&lt;p&gt;What we want is the rate of change between to points, this can be thought of as finding the slope of a line between points. If we think of the &lt;code&gt;font-size&lt;/code&gt; as the &lt;code&gt;y&lt;/code&gt; and the resulting percent as &lt;code&gt;x&lt;/code&gt;, we can find the slope (&lt;code&gt;m&lt;/code&gt;) in the following way:&lt;/p&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.css&quot; integrity=&quot;sha384-WsHMgfkABRyG494OmuiNmkAOk8nhO1qE+Y6wns6v+EoNoTNxrWxYpl5ZYWFOLPCM&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msub&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/msub&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msub&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/msub&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;m=(y_2-y_1)/(x_2-x_1)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Plugging in some numbers from the chart, we get the following:&lt;/p&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.css&quot; integrity=&quot;sha384-WsHMgfkABRyG494OmuiNmkAOk8nhO1qE+Y6wns6v+EoNoTNxrWxYpl5ZYWFOLPCM&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mn&gt;28&lt;/mn&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;25&lt;/mn&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;.1&lt;/mn&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;0&lt;/mn&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;30&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;m=(28-25)/(-.1-0)=-30&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;28&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;25&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.1&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7278em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;30&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;This shouldn’t be a surprise from Mathieu’s post:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/letter-spacing-steps.jpg&quot; alt=&quot;Letter spacing steps&quot;/&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;-30&lt;/code&gt; is related to the &lt;code&gt;30px&lt;/code&gt; every &lt;code&gt;1%&lt;/code&gt; decrease. The next thing we need is the formula that produces all of the &lt;code&gt;x&lt;/code&gt; values based on a given &lt;code&gt;y&lt;/code&gt;. You might remember this formula from school:&lt;/p&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.css&quot; integrity=&quot;sha384-WsHMgfkABRyG494OmuiNmkAOk8nhO1qE+Y6wns6v+EoNoTNxrWxYpl5ZYWFOLPCM&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;y=mx+b&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.625em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;However, we want to solve for &lt;code&gt;x&lt;/code&gt;, so we need to rearrange the terms:&lt;/p&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.css&quot; integrity=&quot;sha384-WsHMgfkABRyG494OmuiNmkAOk8nhO1qE+Y6wns6v+EoNoTNxrWxYpl5ZYWFOLPCM&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;x=(y-b)/m&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;In this formula, &lt;code&gt;y&lt;/code&gt; is our &lt;code&gt;font-size&lt;/code&gt;, and &lt;code&gt;m&lt;/code&gt; is the slope we got earlier of &lt;code&gt;-30&lt;/code&gt;. So what does &lt;code&gt;b&lt;/code&gt; represent? It’s where the slope crosses the x-axis. We could find this by moving terms around again, but Mathieu has already provided this number; &lt;code&gt;25&lt;/code&gt; (for &lt;code&gt;25px&lt;/code&gt; where this calculation starts). Our formula now looks like this:&lt;/p&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.css&quot; integrity=&quot;sha384-WsHMgfkABRyG494OmuiNmkAOk8nhO1qE+Y6wns6v+EoNoTNxrWxYpl5ZYWFOLPCM&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;z&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;25&lt;/mn&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;30&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;percent=(fontsize-25)/-30&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8095em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;erce&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.10764em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ze&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;25&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;30&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;This doesn’t look too intimidating yet, but here’s where it get challenging. We need to turn this into CSS. Let’s try just making some variables for this first:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-function)&quot;&gt;.paragraph&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --b&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 25&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;/** starting size */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --m&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; -30&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;/** rate of change */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --x&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;em&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--b)) / &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--m)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;/** percent? */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    letter-spacing&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; clamp&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        -0.04&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;em&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--ems) * 1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;em&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;em&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    )&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ok, so far all of this &lt;em&gt;should&lt;/em&gt; work. We’re still missing the &lt;code&gt;--ems&lt;/code&gt; assignment but we can subtract unit values from each other, and we can divide a unit number by an unitless number. When we subtract units like this, the result is resolved into a pixel amount. This’ll be important later.&lt;/p&gt;
&lt;h3 id=&quot;the-hard-parts&quot;&gt;The hard parts&lt;/h3&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;We’re about to begin using super new CSS properties in a very hacky way. Consider yourself warned.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;The first problem is that &lt;code&gt;--x&lt;/code&gt; &lt;em&gt;isn’t&lt;/em&gt; a unitless value, it’s a pixel amount. Setting this as the &lt;code&gt;--ems&lt;/code&gt; isn’t correct because in Mathieu’s formula, we want a &lt;em&gt;percent&lt;/em&gt; of the &lt;code&gt;1em&lt;/code&gt;. So we want &lt;code&gt;--x&lt;/code&gt; to have the pixel units removed.&lt;/p&gt;
&lt;p&gt;There’s &lt;a href=&quot;https://dev.to/janeori/css-type-casting-to-numeric-tanatan2-scalars-582j&quot;&gt;a recent trick made popular by Jane Ori&lt;/a&gt; which demonstrates how we might hack CSS to give us unitless values using &lt;code&gt;atan2()&lt;/code&gt;. We’ll need to add a few things:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-keyword)&quot;&gt;@property&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; --x {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  syntax: &amp;quot;&amp;lt;length&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  initial-value&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;: 0px;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  inherits: false;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-function)&quot;&gt;.paragraph&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --b&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 25&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;/** starting size */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --m&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; -30&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;/** rate of change */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --x&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;em&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--b)) / &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--m)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;/** percent? */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    letter-spacing&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; clamp&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        -0.04&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;em&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--ems) * 1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;em&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;em&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    )&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first thing we need is to effectively &lt;em&gt;force&lt;/em&gt; the &lt;code&gt;--x&lt;/code&gt; to give us a pixel amount. It might seem weird that we need to do this since we know it’s resolving as a pixel, but it’ll be important so we can use &lt;code&gt;atan2()&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-keyword)&quot;&gt;@property&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; --x {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  syntax: &amp;quot;&amp;lt;length&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  initial-value&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;: 0px;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  inherits: false;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-function)&quot;&gt;.paragraph&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --b&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 25&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;/** starting size */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --m&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; -30&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;/** rate of change */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --x&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;em&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--b)) / &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--m)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;/** percent? */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --ems&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; tan&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;atan2&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--x)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 16&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;/** percent! */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    letter-spacing: &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        -0.04&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;em&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--ems) * 1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;em&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;em&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You’ll see I’ve added the &lt;code&gt;--ems&lt;/code&gt; variable by using the approach in the blog post. You can essentially look at this as returning &lt;code&gt;--x&lt;/code&gt; in terms of &lt;code&gt;16px&lt;/code&gt; and return the unitless result. What we have will work, but there’s one small problem. I’ve explicitly set &lt;code&gt;16px&lt;/code&gt; here which is assuming base font size as a fixed pixel amount. Entering &lt;code&gt;1rem&lt;/code&gt; in here doesn’t work (and admittedly I’m not entirely sure why even when updating the &lt;code&gt;@property&lt;/code&gt; defaults).&lt;/p&gt;
&lt;p&gt;What we’ll need is &lt;code&gt;1rem&lt;/code&gt; in terms of pixels. Luckily, &lt;a href=&quot;https://codepen.io/propjockey/pen/WNLLLWy&quot;&gt;Jane has that example&lt;/a&gt; in her post. We’ll use another &lt;code&gt;atan2()&lt;/code&gt; to get the &lt;em&gt;unitless&lt;/em&gt; number of pixels per &lt;code&gt;rem&lt;/code&gt; (&lt;code&gt;16&lt;/code&gt;) and expect to replace the &lt;code&gt;16px&lt;/code&gt; with this result. This actually needs a number with a pixel unit so we can do that quickly by multiplying the unitless result of the new &lt;code&gt;atan2()&lt;/code&gt; by &lt;code&gt;1px&lt;/code&gt; to finally resolve to &lt;code&gt;16px&lt;/code&gt;. Here’s the whole working declaration, followed by the codepen:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);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:var(--astro-code-token-keyword)&quot;&gt;@property&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; --x {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  syntax: &amp;quot;&amp;lt;length&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  initial-value&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;: 0px;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  inherits: false;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-keyword)&quot;&gt;@property&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; --rem {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  syntax: &amp;quot;&amp;lt;length&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;&amp;quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;  initial-value&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;: 0px;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;  inherits: false;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-function)&quot;&gt;.paragraph&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --rem&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --b&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 25&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;/** starting size */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --m&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; -30&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;/** rate of change */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --x&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;em&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--b)) / &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--m)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;/** percent? */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    --ems&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; tan&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;atan2&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--x)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        calc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;tan&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;atan2&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--rem)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;))) * 1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    )&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;/** percent! */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    letter-spacing&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; clamp&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        -0.04&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;em&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(--ems) * 1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;em&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;        0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;em&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    )&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;iframe height=&quot;500&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;Dynamic letter spacing test&quot; src=&quot;https://codepen.io/fauxserious/embed/ByByMeN?default-tab=css%2Cresult&quot; frameborder=&quot;no&quot; loading=&quot;lazy&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;&lt;p&gt;See the Pen &lt;a href=&quot;https://codepen.io/fauxserious/pen/ByByMeN&quot;&gt;
Dynamic letter spacing test&lt;/a&gt; by Donnie D’Amato (&lt;a href=&quot;https://codepen.io/fauxserious&quot;&gt;@fauxserious&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 do wonder if there’s a setup that allows us to remove the second &lt;code&gt;atan2()&lt;/code&gt; usage and insert the &lt;code&gt;1rem&lt;/code&gt; directly here but I haven’t found it yet.&lt;/p&gt;
&lt;p&gt;Whew, what a ride! Maybe one day, we’ll get a supported way of dividing values with units to return a unitless value. But for now, we can wish upon this proof-of-concept. Thanks to Mathieu and Jane for their resources!&lt;/p&gt;</content:encoded></item><item><title>Unicorns on the web</title><link>https://blog.damato.design/posts/unicorns-on-the-web</link><guid isPermaLink="true">https://blog.damato.design/posts/unicorns-on-the-web</guid><pubDate>Fri, 19 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;This post is going to be a little different than others, as I expect to update it over time with resources I find about design engineering.&lt;/p&gt;
&lt;h2 id=&quot;designengineerxyz&quot;&gt;&lt;a href=&quot;https://designengineer.xyz&quot;&gt;designengineer.xyz&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is one of the first websites I found dedicated to the recent hype. Launched by &lt;a href=&quot;https://twitter.com/_kejk&quot;&gt;Karl Koch&lt;/a&gt;, it also seems to be one of the most fully covered with design engineering materials and resources such as related posts and jobs.&lt;/p&gt;
&lt;h2 id=&quot;designengineerio&quot;&gt;&lt;a href=&quot;https://designengineer.io&quot;&gt;designengineer.io&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Launched very recently by &lt;a href=&quot;https://twitter.com/moeamaya&quot;&gt;Moe Amaya&lt;/a&gt;. This seems to be specifically a job board and it has a sleek design with many visual doodads. It’s interesting that the bottom of the page says “Job board for design engineers…cause there isn’t one” when there’s one right at the top of this list!&lt;/p&gt;
&lt;h2 id=&quot;designengineering&quot;&gt;&lt;a href=&quot;https://designengineer.ing&quot;&gt;designengineer.ing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Launched by &lt;a href=&quot;https://twitter.com/doctorbaytas&quot;&gt;Dr. Mehmet Aydın Baytaş&lt;/a&gt;. At the time of this writing this only shows an email waitlist. His feed suggests merch will be coming as well.&lt;/p&gt;
&lt;p&gt;At this point we should just check for designengineer.[TLD]! designengineer.wtf is currently &lt;del&gt;available&lt;/del&gt; &lt;a href=&quot;https://twitter.com/bedesqui/status/1782925001941012884&quot;&gt;taken&lt;/a&gt; and I imagine would be a great landing for disambiguating our practice.&lt;/p&gt;
&lt;h2 id=&quot;designerscancodecom&quot;&gt;&lt;a href=&quot;https://designerscancode.com&quot;&gt;designerscancode.com&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Launched by &lt;a href=&quot;https://twitter.com/leemnelson_&quot;&gt;Lee Nelson&lt;/a&gt;. It markets itself as for designers interested in coding; so maybe not precisely what we might describe as a design engineer, but similarly aligned for sure. This also includes a waitlist but seems to have a bit more polish and content than the other waitlist. It also discloses a few more features expected to launch, such as news and learning materials.&lt;/p&gt;
&lt;h2 id=&quot;designtechnologistclub&quot;&gt;&lt;a href=&quot;https://designtechnologist.club&quot;&gt;designtechnologist.club&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This site by &lt;a href=&quot;https://twitter.com/KonstaFe&quot;&gt;Konstantin Fe&lt;/a&gt; which includes a &lt;a href=&quot;https://designtechnologist.club/slack&quot;&gt;slack community&lt;/a&gt;. He has also written a handbook available on the site.&lt;/p&gt;
&lt;h2 id=&quot;designengineer&quot;&gt;&lt;a href=&quot;https://design.engineer&quot;&gt;design.engineer&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This site is shared by &lt;a href=&quot;https://twitter.com/rickwaalders&quot;&gt;Rick Waalders&lt;/a&gt;. At the time of this writing this only shows an email waitlist.&lt;/p&gt;
&lt;h2 id=&quot;uxelab&quot;&gt;&lt;a href=&quot;https://uxelab.com/&quot;&gt;uxe.lab&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Created by &lt;a href=&quot;https://www.michaelposso.com/&quot;&gt;Mike Posso&lt;/a&gt;, it seems to be planned to have frequent challenges and mentorship opportunities to level up peers in the field.&lt;/p&gt;
&lt;h2 id=&quot;designsystemsengineer&quot;&gt;&lt;a href=&quot;https://designsystems.engineer&quot;&gt;designsystems.engineer&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Recent launch by &lt;a href=&quot;https://twitter.com/GarthDB&quot;&gt;Garth Braithwaite&lt;/a&gt; which is currently a newsletter signup. This is meant to be a bit more niche than the others; focusing on design system engineering.&lt;/p&gt;
&lt;h2 id=&quot;uxengineering&quot;&gt;&lt;a href=&quot;https://ux.engineering&quot;&gt;ux.engineering&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There’s nothing at this domain, but I’ll call it out because I own it! Is the space saturated? Is there something that these sites miss? Do I need another project to potentially maintain. All very good questions. &lt;a href=&quot;https://twitter.com/donniedamato/status/1732092177566617915&quot;&gt;What should I do?&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>Wireframe, Backstage</title><link>https://blog.damato.design/posts/wireframe-fm-backstage</link><guid isPermaLink="true">https://blog.damato.design/posts/wireframe-fm-backstage</guid><pubDate>Tue, 26 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;I’ve been an AV nerd for a long time. In one of the first iterations of my personal website, I had something called “Audio Phrekwenci” (pronounced “frequency”), which was an audio blog of sporadic release. I’d record my ramblings to a microphone, edit in some free software, and publish it on my personal server. I had some friends listen to it ever so often and it was fun to talk about.&lt;/p&gt;
&lt;p&gt;Since then, I’ve always had the itch to do it again. But one thing was always holding me back; &lt;strong&gt;editing&lt;/strong&gt;. Traditional editing is painful and time-consuming. Now, that technology has come a long way and text-based editing has appeared, it’s finally time to give it a go in a new show called &lt;a href=&quot;https://wireframe.fm&quot;&gt;Wireframe&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;concept&quot;&gt;Concept&lt;/h2&gt;
&lt;p&gt;The idea was to create a workflow so that once I see an idea or opinion on the internet, I can have the potential to create an episode within 2 hours. Whether or not that happens regularly is not yet determined, but I wanted the ability to respond quickly if appropriate.&lt;/p&gt;
&lt;p&gt;To do this, I needed a tight framework of applications to work together that output all of the resources I’d like to provide. Here’s a list of requirements that I had:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Recording equipment&lt;/strong&gt;, microphone and other devices.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Text-based editing&lt;/strong&gt;, otherwise this just isn’t happening.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cloud-based editing&lt;/strong&gt;, with the option to edit on my tablet.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;.mp3&lt;/code&gt; export&lt;/strong&gt;, seems obvious but needs to be enumerated.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;.srt&lt;/code&gt; export&lt;/strong&gt;, the transcript so contents are eventually searchable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Shownotes editor&lt;/strong&gt;, a way to include shownotes into the episode page.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inexpensive/Free audio hosting&lt;/strong&gt;, not trying to pay for more than I need.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;recording&quot;&gt;Recording&lt;/h2&gt;
&lt;p&gt;As an AV nerd, I have a prosumer setup for recording and streaming audio and video. Below is an image from when I was recording &lt;a href=&quot;https://www.youtube.com/watch?v=V_FfUrmLnQ0&quot;&gt;my talk for UXDX&lt;/a&gt; a few years ago.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/media-cart.jpeg&quot; alt=&quot;Media cart with lots of audio/video devices&quot;/&gt;&lt;/p&gt;
&lt;p&gt;I’ve updated the cart a little bit since then. Nearly all of the devices on the desktop have been replaced with a single &lt;a href=&quot;https://proav.roland.com/global/products/sr-20hd/&quot;&gt;Roland SR-20HD&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;My original plan was to record the media directly to YouTube as unlisted. YouTube provides practically unlimited media storage so I thought this would be a good start. Unfortunately, there’s a few reasons why this didn’t work out.&lt;/p&gt;
&lt;p&gt;First, the result was low quality. It was more apparent when choosing to record as a webcam, but using the encoder was also not great either. It would seem I was subject to data packet loss and I’d need to find another way to record. I also tried to use the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder&quot;&gt;&lt;code&gt;MediaRecorder&lt;/code&gt; API&lt;/a&gt; but that also had a quality issue. Certainly, the web isn’t meant to be handling this sort of data.&lt;/p&gt;
&lt;p&gt;Second, has to do with the next step of editing. I was very interested in using &lt;a href=&quot;https://streamlabs.com/podcast-editor&quot;&gt;Streamlabs Podcast Editor&lt;/a&gt; as the next part of my workflow. One of its features is the ability to start a project by providing a YouTube link. This means that I wouldn’t need to download the file just to upload it to another platform. The products should be able to talk to each other. This worked in practice with an existing link I had. However, when I tried recording and immediately editing that recording, the download was not available. In fact, it was not available for &lt;em&gt;several hours&lt;/em&gt;. This was unacceptable as a primary workflow.&lt;/p&gt;
&lt;p&gt;Because of this recording to YouTube was removed as part of the workflow. I still plan to use the platform for the potential of live events.&lt;/p&gt;
&lt;p&gt;In the end, I record the footage to an SD card and transfer it to a computer for the next step. Not so futuristic, but maybe there’s more to explore here.&lt;/p&gt;
&lt;h2 id=&quot;editing&quot;&gt;Editing&lt;/h2&gt;
&lt;p&gt;Certainly, text-based editing was critical in this process. Streamlabs also offers this and my initial tests were very good. The pricing was also excellent, offering 40 hours of transcription; the most out of any web-based editing service I found. While I looked into &lt;a href=&quot;https://www.descript.com/&quot;&gt;Descript&lt;/a&gt; at the time, the price was more expensive for less hours. Streamlabs also seemed to have everything I wanted in my flow and nothing more; making a much simpler editing experience.&lt;/p&gt;
&lt;p&gt;I also happen to have a subscription to Adobe, and have Adobe Premiere Pro which recently released text-based editing as well. The workflow is a little bit convoluted but I got some good results once I figured out there’s a difference between the source transcript and the timeline transcript. However, this is desktop only. So I wouldn’t be able to edit on my tablet. But this would be a good backup solution, except for one problem.&lt;/p&gt;
&lt;p&gt;My recording equipment outputs a file where Adobe Premiere can’t render audio. I don’t know why this is, as when I play the file anywhere else the audio exists. The only thing I’ve noticed so far is that the audio sampling rate from the equipment is 48000Hz, while all of the other files I have are 44100Hz. Not sure if that’s the issue but, seems like Adobe is just not going to work here.&lt;/p&gt;
&lt;p&gt;When it came time to produce the pilot, I did all of the editing within Streamlabs. Then I went to export the file as an &lt;code&gt;mp3&lt;/code&gt;. The process of doing this was not expected. While I understand I need to have the file encoded, I wasn’t expecting an email with the result. Additionally, that email didn’t have the file within it. It was a link back to the project, which was a page of different links; none of which were &lt;code&gt;mp3&lt;/code&gt; files. The file I was able to download was a &lt;code&gt;.mp4&lt;/code&gt; which was unplayable. I’ve reached out to their support on this and they claim that the &lt;code&gt;mp3&lt;/code&gt; export is possible but it’s not clear.&lt;/p&gt;
&lt;p&gt;Realizing that less and less of my expectations were being met with Streamlabs, I got an account with Descript and re-edited the footage there. The experience was more inline with my expectations; able to receive an &lt;code&gt;.mp3&lt;/code&gt; file and an &lt;code&gt;.srt&lt;/code&gt; file for the episode. It also seems I can record to the platform here as well. I might revisit my workflow to record to the cloud instead of SD card transfer if the quality behaves.&lt;/p&gt;
&lt;h2 id=&quot;hosting&quot;&gt;Hosting&lt;/h2&gt;
&lt;p&gt;This was one of the easiest choices but it took some time to find. I decided to use &lt;a href=&quot;https://www.acast.com/&quot;&gt;Acast&lt;/a&gt; to host the episodes as &lt;a href=&quot;https://www.reddit.com/r/webdev/comments/1b14bty/netlify_just_sent_me_a_104k_bill_for_a_simple/&quot;&gt;I didn’t want to host audio files on Netlify&lt;/a&gt;. The platform has unlimited hosting and downloads of episodes. It also can add an intro &amp;amp; outro to every episode; no need to edit it into the file beforehand. It provides a nicely styled RSS feed.&lt;/p&gt;
&lt;aside data-astro-cid-duqfclob&gt;  &lt;div class=&quot;content&quot; data-astro-cid-duqfclob&gt; &lt;p&gt;Some folks might be wondering about the recorded intro and outro. That was a combination of &lt;a href=&quot;https://elevenlabs.io/&quot;&gt;ElevenLabs&lt;/a&gt; and &lt;a href=&quot;https://studio.youtube.com/&quot;&gt;YouTube Studio Audio Library&lt;/a&gt;, with a small session in Adobe Audition to get the mixdown.&lt;/p&gt; &lt;/div&gt; &lt;/aside&gt;
&lt;p&gt;One thing that I want to mention: &lt;em&gt;do not play with the feed redirect settings&lt;/em&gt;. I made the mistake of testing this out and it took several days for customer service to revert this since you’re unable to go back yourself once you do it. The messaging is misleading in that setting; saying “you can easily reverse the redirection if needed”. Easy means contact customer service, so don’t do that. It’s only needed if you no longer want to use Acast.&lt;/p&gt;
&lt;h2 id=&quot;website&quot;&gt;Website&lt;/h2&gt;
&lt;p&gt;I was heavily inspired by &lt;a href=&quot;https://syntax.fm/&quot;&gt;Syntax&lt;/a&gt;. I truly appreciate those folks providing the site as source code so I can get some ideas on how to provide content about the show.&lt;/p&gt;
&lt;p&gt;While I don’t have all of their bells &amp;amp; whistles, one thing I knew that I wanted was to have the transcript and shownotes combined into a single Markdown file. I had the idea of using Markdown footnote syntax to pepper the transcript with footnote marks. Then the Astro Markdown renderer would automatically create a shownotes section using that syntax.&lt;/p&gt;
&lt;p&gt;This was also the first time I used the new &lt;code&gt;subgrid&lt;/code&gt; syntax for the episodes to get the content alignment between the cards. You won’t notice this until there are more episodes. Setting &lt;code&gt;grid-row: span 2&lt;/code&gt; on the children of the parent grid was the key to making this work.&lt;/p&gt;
&lt;p&gt;Another thing that I created was a page to help create an episode entry for the website from the Acast feed. Once I publish an episode, I can visit a special page on the website that fetches the feed and allows me to add the transcript and tags to create a new &lt;code&gt;.md&lt;/code&gt; file for the website. The submit button creates a PR in Github, and there I can add the shownote markings before publishing. Github has a nice web editor for markdown files where you can preview the result.&lt;/p&gt;
&lt;p&gt;One thing that I needed to consider was that the intro added in Acast would cause all of the transcripts offset to be inaccurate. This means that I’d need to offset the transcript times by the intro seconds. I had made a small function that would update all of the transcript times. That looks like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-color-background);color:var(--astro-code-color-text);overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-comment)&quot;&gt;// Convert a string time into seconds&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; timecodeToSeconds&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(t) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; t&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.split&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;:&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.reduce&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;((acc&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;time) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;60&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; acc) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;time);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-comment)&quot;&gt;// Convert seconds into string time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; secondsToTime&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(seconds) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        parseInt&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(seconds &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 60&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 60&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        parseInt&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(seconds &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 60&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; %&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 60&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        parseInt&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(seconds &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 60&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        .join&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;quot;:&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;        .replace&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;\b&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;(\d)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;\b&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;g&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &amp;quot;0$1&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&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:var(--astro-code-token-comment)&quot;&gt;// Find timecodes, update with the seconds offset&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; timescriptTimeOffset&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(srt&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; offset) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; srt&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.replace&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;/((?:\d&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;:)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;\d&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;,\d&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;)/&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;gm&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; (m) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;        const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;code&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; ms&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; m&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.split&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;        const&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; time&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; timecodeToSeconds&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(code) &lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; Number&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(offset);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;secondsToTime&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(time)&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt; ms]&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.join&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, for now the workflow is: record to SD card, edit in Descript, publish on Acast, and finalize through Github.&lt;/p&gt;
&lt;h2 id=&quot;stop-collaborate-and-listen&quot;&gt;Stop, collaborate, and listen&lt;/h2&gt;
&lt;p&gt;And that’s it! The pilot is out, and I plan to have a new episode at least once a week for the next few months. You can also follow &lt;a href=&quot;https://twitter.com/wireframefm&quot;&gt;&lt;code&gt;@wireframefm&lt;/code&gt;&lt;/a&gt; on Twitter. I expect to add syndications in the next week or so to your favorite platforms.&lt;/p&gt;</content:encoded></item><item><title>Your first component</title><link>https://blog.damato.design/posts/your-first-component</link><guid isPermaLink="true">https://blog.damato.design/posts/your-first-component</guid><pubDate>Fri, 10 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!DOCTYPE html&gt;&lt;p&gt;&lt;a href=&quot;https://bsky.app/profile/cory.laviska.com&quot;&gt;Cory LaViska&lt;/a&gt; of &lt;a href=&quot;https://shoelace.style/&quot;&gt;Shoelace&lt;/a&gt; fame posted this a few days ago:&lt;/p&gt;
&lt;blockquote class=&quot;blockquote&quot; cite=&quot;https://bsky.app/profile/cory.laviska.com/post/3lfczce754k2d&quot; data-astro-cid-arj5dyob&gt; &lt;div class=&quot;quote&quot; data-astro-cid-arj5dyob&gt; &lt;p&gt;when building a component library, what component do you build first and why is it always button?&lt;/p&gt; &lt;/div&gt; &lt;span data-astro-cid-arj5dyob&gt;— &lt;a href=&quot;https://bsky.app/profile/cory.laviska.com/post/3lfczce754k2d&quot; data-astro-cid-arj5dyob&gt; &lt;cite data-astro-cid-arj5dyob&gt;Cory LaViska&lt;/cite&gt;&lt;/a&gt;&lt;/span&gt; &lt;/blockquote&gt;
&lt;p&gt;It’s a similar question that starts &lt;a href=&quot;https://www.youtube.com/watch?v=PkHCk36hMik&quot;&gt;Dan Mall’s talk he first performed at Clarity 2022&lt;/a&gt;. Dan argues that the button doesn’t provide impact to teams; buttons are easy and obvious. It would be more useful to determine what component would be the most impactful and then contribute that to the business. In Dan’s talk, he uses the example of a map component for Uber which is essential to the experience and wildly complex. I disagree that the map is a good choice for the design systems team to tackle, but I agree with the sentiment of prioritizing impact.&lt;/p&gt;
&lt;p&gt;However, for folks that are dipping their toes into design systems, Cory’s question is interesting. Why is the button the first thing most folks build?&lt;/p&gt;
&lt;h2 id=&quot;popularity&quot;&gt;Popularity&lt;/h2&gt;
&lt;p&gt;I was having a dinner conversation with &lt;a href=&quot;https://www.adekunleoduye.com/&quot;&gt;Adekunle Oduye&lt;/a&gt; one evening where I was asking him a similar question; how do we choose what components belong in a design system? For many folks, we’d look at existing systems and inventory what the most popular components are. Looking at &lt;a href=&quot;https://component.gallery/&quot;&gt;component.gallery&lt;/a&gt;, Button is the most popular component with 141 examples at the time of this writing. It would make sense that because it is the most popular component, it probably belongs in your system too.&lt;/p&gt;
&lt;p&gt;But this should introduce a new question. When the first design systems were starting, how did &lt;em&gt;they&lt;/em&gt; know they needed these components? The answer is doing their own inventory local to their companies’ needs. In fact, that’s ultimately what Dan is suggesting in his talk. The design system should be a reflection of the people it is made for. So what components you maintain should be determined by an internal inventory of usage.&lt;/p&gt;
&lt;p&gt;It is easy to tie impact to how often something is needed. The more it is needed, the more it impacts the final result. Therefore, because the button tends to be the most popular, we tend to want to build it first.&lt;/p&gt;
&lt;h2 id=&quot;necessity&quot;&gt;Necessity&lt;/h2&gt;
&lt;p&gt;Since we want interactive websites, we expect that we will need a button at the very least, even if that button operates as a link. Without interactivity, a website is a one-sided conversation. There’s no navigation, no feedback. It might as well be a piece of paper to be read once and maybe bookmarked for later. To begin turning a web page into something a little more, that interactivity is needed.&lt;/p&gt;
&lt;p&gt;Importantly, I don’t believe small sites need design systems. In fact, most of the personal websites I’ve created don’t have a design system; just some reusable styles. Larger sites beget interactivity to traverse between the homepage, dashboard, products, checkout, and beyond. Each one of those pages is expecting a user to achieve some goal. To do that, the user needs to make choices, and those choices are coded as moments of interactivity within buttons, among other controls.&lt;/p&gt;
&lt;h2 id=&quot;complexity&quot;&gt;Complexity&lt;/h2&gt;
&lt;p&gt;So far, I’ve been making a case for why you’ll probably need a button in your system. I haven’t yet touched upon why it’s most likely first.&lt;/p&gt;
&lt;p&gt;The button component is deviously complex in the number of states and priorities it could be meant to convey. When we alter a single presentational attribute, it could convey a whole new meaning to the user. This is especially apparent by the way we’ve landed on our common naming system for buttons. In other words, &lt;strong&gt;the button is the only interactive control that can convey priority&lt;/strong&gt;. There is no such thing as a “primary” text field. As an example, the primary button is meant to guide the user to the most likely direction they should take.&lt;/p&gt;
&lt;p&gt;Getting all the visual treatments right such that they convey the correct information can be a daunting exercise for folks unfamilar with the permutations. However, this is also the &lt;em&gt;only&lt;/em&gt; hard part about the button. There’s really only one thing the button can do, accept a click. So we can focus our attention on the visual treatment alone. Which leads to the next reason.&lt;/p&gt;
&lt;h2 id=&quot;containment&quot;&gt;Containment&lt;/h2&gt;
&lt;p&gt;The button is mostly often considerd an “atomic” component, meaning it is commonly not broken down to further elements. Many other components are composed of other pieces and with each additional piece added to a component, more complexity is added. So not only would a person need to make decisions on the visual treatment of each part, you’d also need to make decisions on how these pieces work between themselves and in some cases within the larger composition they’ll be set within.&lt;/p&gt;
&lt;p&gt;Since the button is self-contained and has no real complexity past the various visual treatments, we tend to tackle this low-hanging fruit first as a quick win.&lt;/p&gt;
&lt;h2 id=&quot;tokens&quot;&gt;Tokens&lt;/h2&gt;
&lt;p&gt;The final note to mention is that we often spend a great deal of time curating tokens, either by choosing names or their values. In order to test our architectures, it would be most helpful to assign these tokens to something that can show coverage easily. The button having lots of potential in visual complexity and customization, while being a small self-contained component, makes it a excellent “test” component to build where you can curate your token architectures and check the visual result in something you have confidence will appear on any page.&lt;/p&gt;
&lt;p&gt;So all of these things contribute to the reason why I believe the button tends to be first in our libraries. In &lt;a href=&quot;https://system.damato.design/&quot;&gt;my system playground&lt;/a&gt;, it was probably the first “non-primitive” component.&lt;/p&gt;</content:encoded></item></channel></rss>