<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Marco Solazzi</title>
    <description>The latest articles on DEV Community by Marco Solazzi (@dwightjack).</description>
    <link>https://dev.to/dwightjack</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F153749%2F967635dc-c91b-49f0-be64-62755989f848.jpeg</url>
      <title>DEV Community: Marco Solazzi</title>
      <link>https://dev.to/dwightjack</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dwightjack"/>
    <language>en</language>
    <item>
      <title>A Journey through Switches</title>
      <dc:creator>Marco Solazzi</dc:creator>
      <pubDate>Thu, 27 Feb 2025 05:45:36 +0000</pubDate>
      <link>https://dev.to/dwightjack/a-journey-through-switches-3fdd</link>
      <guid>https://dev.to/dwightjack/a-journey-through-switches-3fdd</guid>
      <description>&lt;p&gt;&lt;em&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; This post is just a record of my tests, investigations and speculations. Things might evolve and change as technology changes. Remember to verify your assumptions and test your code.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Some time ago, I learned about an interesting HTML pattern by wandering through &lt;a href="https://html.spec.whatwg.org/" rel="noopener noreferrer"&gt;the spec&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"btn"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Hello World&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"btn"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What I didn't know until then is that &lt;code&gt;button&lt;/code&gt; is a &lt;a href="https://html.spec.whatwg.org/multipage/forms.html#category-label" rel="noopener noreferrer"&gt;labelable element&lt;/a&gt; and thus it can be referenced with the &lt;code&gt;for&lt;/code&gt; attribute of a &lt;code&gt;label&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Since this looked like an exotic pattern to me, I did some research and found that the pattern is actually well supported by browsers and most screen readers but not so well supported by voice control software (even if I couldn't verify it myself). &lt;/p&gt;

&lt;p&gt;My initial guess was that, depending on the requirements, there are probably more established patterns out there, like using &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;aria-labelledby&lt;/code&gt;. Nonetheless, this pattern stuck in my mind.&lt;/p&gt;

&lt;h2&gt;
  
  
  And then came The Switch
&lt;/h2&gt;

&lt;p&gt;Now, the example above doesn't make much sense, and I didn't encounter it &lt;em&gt;in the wild&lt;/em&gt; until recently when I found an implementation of it looking at the examples of the &lt;code&gt;Switch&lt;/code&gt; component in the &lt;a href="https://ui.shadcn.com/docs/components/switch" rel="noopener noreferrer"&gt;shadcn documentation&lt;/a&gt; (I cleaned it up to make it more readable):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; 
    &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; 
    &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"switch"&lt;/span&gt; 
    &lt;span class="na"&gt;aria-checked=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt; 
    &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"on"&lt;/span&gt; 
    &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"airplane-mode"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"airplane-mode"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Airplane Mode&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The markup is very close to my first snippet, with the relevant addition of the &lt;code&gt;switch&lt;/code&gt; role and the related &lt;code&gt;aria-checked&lt;/code&gt; attribute. These additions tell assistive technologies that the control is a &lt;a href="https://www.w3.org/TR/wai-aria/#switch" rel="noopener noreferrer"&gt;switch&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Around the web, you might find the control also called toggle or toggle switch, but this is how it would usually look like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frokk6lg9h182r06v9nlp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frokk6lg9h182r06v9nlp.png" alt="Two user interface switches in on and off state" width="60" height="65"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since shadcn is based on &lt;a href="https://www.radix-ui.com/primitives" rel="noopener noreferrer"&gt;Radix UI&lt;/a&gt;, a pretty established React library with a focus on accessibility, I decided to embark on a journey to see what other popular libraries were doing and how widespread the &lt;em&gt;labeled button&lt;/em&gt; pattern was.&lt;/p&gt;

&lt;h3&gt;
  
  
  Introduction to switches
&lt;/h3&gt;

&lt;p&gt;Before starting the journey, let's try to understand what a switch is, because the control itself is also pretty interesting from a User Experience point of view. &lt;/p&gt;

&lt;p&gt;It clearly is a &lt;a href="https://www.interaction-design.org/literature/topics/skeuomorphism" rel="noopener noreferrer"&gt;skeuomorphism&lt;/a&gt; of physical &lt;a href="https://en.wikipedia.org/wiki/Switch#Toggle_switch" rel="noopener noreferrer"&gt;toggle switches&lt;/a&gt; and it was probably popularized by the &lt;a href="https://developer.apple.com/design/human-interface-guidelines/toggles" rel="noopener noreferrer"&gt;iOS interface&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;In many cases, the expected behavior for this control is to immediately have an effect on the system. For example, we expect a switch for airplane mode to immediately turn it on or off without having to press a save button. &lt;/p&gt;

&lt;p&gt;This is where the application of this UI pattern to the web changes: a switch can both have immediate effect or be part of a submittable form (thus behaving almost like a checkbox). Let's keep this in mind for later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Web switches
&lt;/h3&gt;

&lt;p&gt;When it comes to the web, there's extensive literature about accessible switches and toggle buttons (for example: &lt;a href="https://www.scottohara.me/note/2019/04/03/switch-script.html" rel="noopener noreferrer"&gt;Updated Switch script &amp;amp; more&lt;/a&gt;, &lt;a href="https://inclusive-components.design/toggle-button/" rel="noopener noreferrer"&gt;Toggle Buttons&lt;br&gt;
&lt;/a&gt;, &lt;a href="https://kittygiraudel.com/2021/04/05/an-accessible-toggle/#button-variant" rel="noopener noreferrer"&gt;An accessible toggle&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Even if their semantics are slightly different, the names are &lt;a href="https://component.gallery/components/toggle/" rel="noopener noreferrer"&gt;used interchangeably in design systems&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;There are two ongoing initiatives for native switch controls: &lt;a href="https://open-ui.org/components/switch.explainer/" rel="noopener noreferrer"&gt;OpenUI toggle&lt;/a&gt; and &lt;a href="https://github.com/whatwg/html/pull/9546" rel="noopener noreferrer"&gt;switch attribute&lt;/a&gt;, the latter one being &lt;a href="https://webkit.org/blog/15054/an-html-switch-control/" rel="noopener noreferrer"&gt;already shipped in Safari 17.4&lt;/a&gt;. But for now, the most effective patterns are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- 1) HTML base is a checkbox --&amp;gt;&lt;/span&gt;  
&lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"switch"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Airplane mode&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"switch"&lt;/span&gt; &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"switch"&lt;/span&gt; &lt;span class="na"&gt;aria-checked=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- 2) HTML base is a button --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"switch-label"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Airplane mode&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;aria-labelledby=&lt;/span&gt;&lt;span class="s"&gt;"switch-label"&lt;/span&gt; &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"switch"&lt;/span&gt; &lt;span class="na"&gt;aria-checked=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/button&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;h4&gt;
  
  
  Screen readers
&lt;/h4&gt;

&lt;p&gt;For both patterns, NVDA and VoiceOver (macOS) and other screen readers would sound like (you can check it on &lt;a href="https://codepen.io/marco_solazzi/full/jENojxL" rel="noopener noreferrer"&gt;CodePen&lt;/a&gt;):&lt;/p&gt;

&lt;pre&gt;
Airplane mode off switch
&lt;/pre&gt;

&lt;p&gt;Not all screen readers/browser pairs support these patterns though. For example, Narrator in every browser except Edge identifies the switch as &lt;code&gt;button, off&lt;/code&gt; (probably because Narrator is mostly tailored for Edge users): as always, build with your target audience in mind.&lt;/p&gt;

&lt;h4&gt;
  
  
  System architecture
&lt;/h4&gt;

&lt;p&gt;From a system architecture perspective, the first pattern is probably preferable in cases where the switch's state change is part of a submittable form. This is because &lt;b&gt;the checkbox's value is submitted with all other fields&lt;/b&gt; (which is a good practice for progressive enhancement). This approach becomes even more relevant with concepts like &lt;a href="https://react.dev/reference/react-dom/components/form#handle-form-submission-with-a-server-function" rel="noopener noreferrer"&gt;React Server Functions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The second pattern is instead more suitable when we want the state change to have an &lt;b&gt;immediate effect&lt;/b&gt; since that's an expected behavior of the underlying &lt;code&gt;button&lt;/code&gt; element.  &lt;/p&gt;

&lt;h4&gt;
  
  
  The "labeled control side effect"
&lt;/h4&gt;

&lt;p&gt;Another big difference, at least from the user agent point of view, is that in the first example the &lt;code&gt;label&lt;/code&gt; has an associated &lt;a href="https://html.spec.whatwg.org/multipage/forms.html#labeled-control" rel="noopener noreferrer"&gt;labeled control&lt;/a&gt; (the checkbox), while in the second &lt;strong&gt;it's just a caption for the button&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It might seem a semantic subtlety, but there is a rather interesting side effect: interacting with the label of a labeled control &lt;strong&gt;triggers events on the control itself&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;For example, in most browsers, clicking the label of a checkbox will change the checkbox's state, as if we directly clicked on the control. This is not the case when we associate a label and a control using &lt;code&gt;aria-labelledby&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So, if we change the second snippet to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- 2) HTML base is a button --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"switch-btn"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Airplane mode&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"switch-btn"&lt;/span&gt; &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"switch"&lt;/span&gt; &lt;span class="na"&gt;aria-checked=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;now clicking on the label triggers the button &lt;code&gt;click&lt;/code&gt; event (you can test the behavior in &lt;a href="https://codepen.io/marco_solazzi/pen/bNGEgPM" rel="noopener noreferrer"&gt;this CodePen&lt;/a&gt;). &lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/marco_solazzi/embed/bNGEgPM?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In the context of a form with many inputs, this behavior might contribute to the consistency of the user experience by making the switch feel more &lt;em&gt;native&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;Anyway, as I previously mentioned, some accessibility software might not fully support this pattern. We'll see later how component libraries are trying to solve the problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Switches in the wild
&lt;/h2&gt;

&lt;p&gt;Now that we've covered the basics of switches and their implementation patterns, I'd like to see what other popular component libraries are doing for the same component. &lt;/p&gt;

&lt;p&gt;I will focus on React, Vue, and Angular since they seem to &lt;a href="https://2024.stateofjs.com/en-US/libraries/front-end-frameworks/" rel="noopener noreferrer"&gt;have the highest market share&lt;/a&gt; in the JavaScript ecosystem. My choice of library is a mix of &lt;a href="https://2024.stateofreact.com/en-US/libraries/component-libraries/" rel="noopener noreferrer"&gt;surveys&lt;/a&gt; and other &lt;a href="https://bestofjs.org/projects?page=1&amp;amp;limit=30&amp;amp;tags=component&amp;amp;sort=monthly-downloads" rel="noopener noreferrer"&gt;sources&lt;/a&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  React Libraries
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Library&lt;/th&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://mui.com/material-ui/react-switch/#label" rel="noopener noreferrer"&gt;MUI&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;label &amp;gt; input[type=checkbox]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://ui.shadcn.com/docs/components/switch" rel="noopener noreferrer"&gt;shadcn/ui + Radix Primitives&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;label[for] + button[role=switch]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://headlessui.com/react/switch#adding-a-label" rel="noopener noreferrer"&gt;Headless UI&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;label[for] + button[role=switch][aria-labelledby]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://chakra-ui.com/docs/components/switch" rel="noopener noreferrer"&gt;Chakra UI&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;label &amp;gt; input[type=checkbox]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://react-spectrum.adobe.com/react-aria/Switch.html" rel="noopener noreferrer"&gt;React Aria&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;label &amp;gt; input[type=checkbox][role=switch]&lt;/code&gt; (no aria-checked)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Vue Libraries
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Library&lt;/th&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://vuetifyjs.com/en/components/switches/#usage" rel="noopener noreferrer"&gt;Vuetify&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;label[for] + input[type=checkbox]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://element-plus.org/en-US/component/form.html" rel="noopener noreferrer"&gt;Element Plus&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;label[for] + input[type=checkbox][role=switch]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://www.radix-vue.com/components/switch.html" rel="noopener noreferrer"&gt;Radix Vue&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;label[for] + button[role=switch][aria-label]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Angular Libraries
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Library&lt;/th&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://material.angular.io/components/slide-toggle/overview" rel="noopener noreferrer"&gt;Angular Material&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;label[for] + button[role=switch][aria-labelledby]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://akveo.github.io/nebular/docs/components/toggle/examples#nbtogglecomponent" rel="noopener noreferrer"&gt;Nebular&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;label &amp;gt; input[type=checkbox][role=switch]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Multi-framework Libraries
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Library&lt;/th&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://getbootstrap.com/docs/5.3/forms/checks-radios/#switches" rel="noopener noreferrer"&gt;Bootstrap&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;label[for] + input[type=checkbox][role=switch]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://www.primefaces.org/" rel="noopener noreferrer"&gt;Prime(NG,React,Vue)&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;label[for] + input[type=checkbox][role=switch]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://ark-ui.com/react/docs/components/switch" rel="noopener noreferrer"&gt;Ark UI&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;label[for] +  input[type=checkbox][aria-labelledby]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;p&gt;After investigating these libraries, a clear result emerges: as I suspected, &lt;strong&gt;most of the library authors chose a more conservative pattern&lt;/strong&gt; using a &lt;code&gt;label&lt;/code&gt; and a checkbox with (or without) the &lt;code&gt;switch&lt;/code&gt; role. &lt;/p&gt;

&lt;p&gt;However, even if it might seem that the &lt;code&gt;label + button&lt;/code&gt; pattern isn't used a lot, we need to remember that React is the most popular JavaScript library, &lt;a href="https://npmtrends.com/@headlessui/react-vs-@mui/material-vs-@radix-ui/primitive-vs-react-bootstrap" rel="noopener noreferrer"&gt;shadcn and Radix have large adoption&lt;/a&gt;, and Headless UI is used in &lt;a href="https://tailwindui.com/components" rel="noopener noreferrer"&gt;Tailwind's own premium UI library&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;So, from a numerical perspective, there may be a significant number of web applications using the &lt;em&gt;labeled button&lt;/em&gt; pattern.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accessibility testing results
&lt;/h3&gt;

&lt;p&gt;In my quick tests using VoiceOver (macOS), NVDA, and Narrator, all these patterns worked as expected. The screen readers correctly reported switches and checkboxes along with their states, with one exception: NVDA on Firefox reports Element Plus as &lt;code&gt;blank&lt;/code&gt;. I didn't investigate this issue in depth, but it might be related to how the library hides the native input element (see a &lt;a href="https://github.com/nvaccess/nvda/discussions/16398" rel="noopener noreferrer"&gt;similar topic for PrimeFaces&lt;/a&gt;). &lt;/p&gt;

&lt;p&gt;
  Tests output log
  &lt;ul&gt;
&lt;li&gt;MUI

&lt;ul&gt;
&lt;li&gt;Safari 18 + VoiceOver: Airplane mode unchecked checkbox&lt;/li&gt;
&lt;li&gt;Chrome 133 + VoiceOver: Airplane mode unchecked checkbox&lt;/li&gt;
&lt;li&gt;Chrome 133  + NVDA 2024.1: Airplane mode checkbox not checked&lt;/li&gt;
&lt;li&gt;Firefox 135 + NVDA 2024.1: clickable Airplane mode checkbox not checked&lt;/li&gt;
&lt;li&gt;Edge 133 + Narrator: Airplane mode checkbox unchecked&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;shadcn/ui + Radix Primitives

&lt;ul&gt;
&lt;li&gt;Safari 18 + VoiceOver: Airplane Mode off switch&lt;/li&gt;
&lt;li&gt;Chrome 133  + VoiceOver: Airplane Mode off switch&lt;/li&gt;
&lt;li&gt;Chrome 133  + NVDA 2024.1: Airplane Mode switch off&lt;/li&gt;
&lt;li&gt;Firefox 135 + NVDA 2024.1: Airplane Mode switch off&lt;/li&gt;
&lt;li&gt;Edge 133 + Narrator: Airplane Mode switch off&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Headless UI

&lt;ul&gt;
&lt;li&gt;Safari 18 + VoiceOver: Airplane mode off switch&lt;/li&gt;
&lt;li&gt;Chrome 133 + VoiceOver: Airplane mode off switch&lt;/li&gt;
&lt;li&gt;Chrome 133  + NVDA 2024.1: Airplane Mode switch off&lt;/li&gt;
&lt;li&gt;Firefox 135 + NVDA 2024.1: Airplane Mode switch off&lt;/li&gt;
&lt;li&gt;Edge 133 + Narrator: Airplane Mode switch off&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Chakra UI

&lt;ul&gt;
&lt;li&gt;Safari 18 + VoiceOver: Airplane mode unchecked checkbox&lt;/li&gt;
&lt;li&gt;Chrome 133 + VoiceOver: Airplane mode unchecked checkbox&lt;/li&gt;
&lt;li&gt;Chrome 133  + NVDA 2024.1: clickable Airplane mode checkbox not checked&lt;/li&gt;
&lt;li&gt;Firefox 135 + NVDA 2024.1: clickable Airplane mode checkbox not checked&lt;/li&gt;
&lt;li&gt;Edge 133 + Narrator: Airplane mode checkbox unchecked&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;React Aria &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Safari 18 + VoiceOver: Airplane mode off switch&lt;/li&gt;
&lt;li&gt;Chrome 133 + VoiceOver: Airplane mode off switch&lt;/li&gt;
&lt;li&gt;Chrome 133  + NVDA 2024.1: clickable Airplane switch off&lt;/li&gt;
&lt;li&gt;Firefox 135 + NVDA 2024.1: clickable Airplane switch off&lt;/li&gt;
&lt;li&gt;Edge 133 + Narrator: Airplane mode off switch&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Vuetify&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Safari 18 + VoiceOver: Airplane mode unchecked checkbox&lt;/li&gt;
&lt;li&gt;Chrome 133 + VoiceOver: Airplane mode unchecked checkbox&lt;/li&gt;
&lt;li&gt;Chrome 133  + NVDA 2024.1: clickable Airplane mode checkbox not checked&lt;/li&gt;
&lt;li&gt;Firefox 135 + NVDA 2024.1: clickable Airplane mode checkbox not checked&lt;/li&gt;
&lt;li&gt;Edge 133 + Narrator: Airplane mode checkbox unchecked&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Element Plus&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Safari 18 + VoiceOver: Airplane Mode off switch&lt;/li&gt;
&lt;li&gt;Chrome 133  + VoiceOver: Airplane Mode off switch&lt;/li&gt;
&lt;li&gt;Chrome 133  + NVDA 2024.1: clickable Airplane Mode switch off&lt;/li&gt;
&lt;li&gt;Firefox 135 + NVDA 2024.1: blank&lt;/li&gt;
&lt;li&gt;Edge 133 + Narrator: Airplane Mode switch off&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Radix Vue&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Safari 18 + VoiceOver: Airplane mode off switch&lt;/li&gt;
&lt;li&gt;Chrome 133 + VoiceOver: Airplane mode off switch&lt;/li&gt;
&lt;li&gt;Chrome 133  + NVDA 2024.1: Airplane Mode switch off&lt;/li&gt;
&lt;li&gt;Firefox 135 + NVDA 2024.1: Airplane Mode switch off&lt;/li&gt;
&lt;li&gt;Edge 133 + Narrator: Airplane Mode switch off&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Angular Material&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Safari 18 + VoiceOver: Airplane Mode off switch&lt;/li&gt;
&lt;li&gt;Chrome 133 + VoiceOver: Airplane Mode off switch&lt;/li&gt;
&lt;li&gt;Chrome 133  + NVDA 2024.1: Airplane Mode switch off&lt;/li&gt;
&lt;li&gt;Firefox 135 + NVDA 2024.1: Airplane Mode switch off&lt;/li&gt;
&lt;li&gt;Edge 133 + Narrator: Airplane Mode switch off&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Nebular&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Safari 18 + VoiceOver: Airplane Mode off switch&lt;/li&gt;
&lt;li&gt;Chrome 133  + VoiceOver: Airplane Mode off switch&lt;/li&gt;
&lt;li&gt;Chrome 133  + NVDA 2024.1: Airplane Mode switch off&lt;/li&gt;
&lt;li&gt;Firefox 135 + NVDA 2024.1: clickable Airplane Mode switch off&lt;/li&gt;
&lt;li&gt;Edge 133 + Narrator: Airplane Mode switch off&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;



&lt;/p&gt;

&lt;p&gt;I created some rough demo environments, grouping most of the libraries I tested. You can check them out at the following links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://stackblitz.com/edit/stackblitz-starters-nia25dtm?file=src%2Fapp%2Fpage.tsx" rel="noopener noreferrer"&gt;React Libraries&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackblitz.com/edit/vitejs-vite-v3yn29k8?file=src%2FApp.vue" rel="noopener noreferrer"&gt;Vue Libraries&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackblitz.com/edit/stackblitz-starters-pgadhces?file=src%2Fapp%2Fapp.component.html" rel="noopener noreferrer"&gt;Angular Libraries&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also noticed some interesting details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MUI, Vuetify, and Chakra UI (as well as Ark UI, which is developed under the same org) implementations of the switch are basically &lt;b&gt;just visual&lt;/b&gt;: the underlying controls are simply labeled checkboxes. While this makes the accessibility information less consistent with its on-screen appearance, as &lt;a href="https://mui.com/material-ui/react-switch/#accessibility" rel="noopener noreferrer"&gt;MUI documentation states&lt;/a&gt;, the choice of not using the switch role is conservative, to widen the range of supported devices.&lt;/li&gt;
&lt;li&gt;React Aria doesn't set the &lt;code&gt;aria-checked&lt;/code&gt; attribute that &lt;a href="https://www.w3.org/TR/wai-aria/#switch" rel="noopener noreferrer"&gt;should be required&lt;/a&gt;; nevertheless, in all my tests, screen readers were able to pick the state from the underlying checkbox.&lt;/li&gt;
&lt;li&gt;Headless UI and Angular Material use the same implementation as shadcn/ui (the &lt;em&gt;labeled button&lt;/em&gt;) but with a twist: they introduce a redundancy where the label is referenced in the button via the &lt;code&gt;aria-labelledby&lt;/code&gt; attribute.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Redundant labeling
&lt;/h3&gt;

&lt;p&gt;The redundant labeling pattern from the previous section  deserves a closer look, as it represents an interesting approach to usability and accessibility.&lt;/p&gt;

&lt;p&gt;Here is a simplified snippet as reference:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"switch"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"switch-label"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Airplane mode&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"switch"&lt;/span&gt; &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"switch"&lt;/span&gt; &lt;span class="na"&gt;aria-labelledby=&lt;/span&gt;&lt;span class="s"&gt;"switch-label"&lt;/span&gt; &lt;span class="na"&gt;aria-checked=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Earlier we said that some accessibility software might not properly compute the name of buttons associated with labels with the &lt;code&gt;for&lt;/code&gt; attribute, so, since &lt;code&gt;aria-*&lt;/code&gt; attributes have precedence in the &lt;a href="https://www.stefanjudis.com/today-i-learned/the-order-of-accessible-name-computation-steps/" rel="noopener noreferrer"&gt;computation of accessible names&lt;/a&gt;, we should have solved those issues. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;for&lt;/code&gt; attribute is then only used to &lt;b&gt;leverage the labeled control trigger side effect&lt;/b&gt; (as &lt;a href="https://github.com/tailwindlabs/headlessui/pull/2265" rel="noopener noreferrer"&gt;reported in this PR&lt;/a&gt;). &lt;/p&gt;

&lt;p&gt;Anyway, I couldn't test the accessibility of this pattern, so &lt;strong&gt;I can't 100% vouch for it&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;p&gt;After this long journey through switch implementations, I can summarize my findings in four key insights:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;em&gt;labeled button&lt;/em&gt; pattern, while fascinating to discover in the HTML spec, remains somehow exotic in practice. However, its usage with a redundant labeling could make it a fair alternative to more traditional patterns.&lt;/li&gt;
&lt;li&gt;Because UI libraries abstract away the HTML implementation, you end up living in a world (that of &lt;code&gt;&amp;lt;Switches /&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;Tabs /&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;Menubar /&amp;gt;&lt;/code&gt;) disconnected from the real medium you're writing for: In all the test scenarios you are writing a variation on &lt;code&gt;&amp;lt;Switch /&amp;gt;&lt;/code&gt; but the &lt;em&gt;real&lt;/em&gt; markup is hidden away. &lt;/li&gt;
&lt;li&gt;When we delegate our design choices to someone else, &lt;strong&gt;we don't know the impact on the user experience&lt;/strong&gt;. Small changes in the markup can fundamentally change how users perceive and interact with an interface.&lt;/li&gt;
&lt;li&gt;The libraries I explored emphasize their accessibility and indeed provide a good baseline, but as we've seen, there are often many possible ways to make a control "accessible" — each with its own assumptions and caveats. Don't rely blindly on any library; &lt;strong&gt;do some research based on your specific needs&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Originally posted at: &lt;a href="https://marco.solazzi.me/blog/journey-through-switches/" rel="noopener noreferrer"&gt;https://marco.solazzi.me/blog/journey-through-switches/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>html</category>
      <category>ui</category>
      <category>a11y</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Not Everything Needs a Component</title>
      <dc:creator>Marco Solazzi</dc:creator>
      <pubDate>Mon, 25 Nov 2024 00:00:00 +0000</pubDate>
      <link>https://dev.to/dwightjack/not-everything-needs-a-component-1hm1</link>
      <guid>https://dev.to/dwightjack/not-everything-needs-a-component-1hm1</guid>
      <description>&lt;p&gt;In the early 2000s, a new term, &lt;a href="https://en.wiktionary.org/wiki/divitis" rel="noopener noreferrer"&gt;&lt;em&gt;Divitis&lt;/em&gt;&lt;/a&gt;, was coined to refer to &lt;q&gt;The practice of authoring web-page code with many div elements in place of meaningful semantic HTML elements&lt;/q&gt;. This was part of an effort to increase awareness of semantics in HTML within the frame of the &lt;a href="https://alistapart.com/article/testdriven/" rel="noopener noreferrer"&gt;Progressive Enhancement&lt;/a&gt; technique.&lt;/p&gt;

&lt;p&gt;Fast forward 20 years - I witness a new &lt;em&gt;syndrome&lt;/em&gt; affecting web developers, one I call &lt;em&gt;componentitis&lt;/em&gt;. Here is my made-up definition:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Componentitis&lt;/strong&gt;: the practice of creating a component for every aspect of a UI in place of a simpler and more reusable solution.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Components
&lt;/h2&gt;

&lt;p&gt;So, first of all, what is a &lt;em&gt;component&lt;/em&gt;? I think React popularized the term to refer to its building blocks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;React lets you combine your markup, CSS, and JavaScript into custom "components", &lt;strong&gt;reusable UI elements for your app.&lt;/strong&gt;&lt;br&gt;
— &lt;em&gt;React documentation - &lt;a href="https://react.dev/learn/your-first-component#:~:text=React%20lets%20you%20combine%20your%20markup%2C%20CSS%2C%20and%20JavaScript%20into%20custom%20%E2%80%9Ccomponents%E2%80%9D%2C%20reusable%20UI%20elements%20for%20your%20app" rel="noopener noreferrer"&gt;Your First Component&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While the concept of reusable UI elements wasn’t new at the time (in CSS, we already had techniques like &lt;a href="https://www.smashingmagazine.com/2011/12/an-introduction-to-object-oriented-css-oocss/" rel="noopener noreferrer"&gt;OOCSS&lt;/a&gt;, &lt;a href="https://smacss.com/" rel="noopener noreferrer"&gt;SMACSS&lt;/a&gt;, and &lt;a href="https://en.bem.info/methodology/quick-start/" rel="noopener noreferrer"&gt;BEM&lt;/a&gt;), the key difference is its original approach to the location of markup, style, and interaction. With React components (and all the subsequent UI libraries), it’s possible to &lt;a href="https://kentcdodds.com/blog/colocation" rel="noopener noreferrer"&gt;co-locate&lt;/a&gt; everything in a single file within the boundaries of a component. &lt;/p&gt;

&lt;p&gt;So, using Facebook’s latest CSS library &lt;a href="https://stylexjs.com/" rel="noopener noreferrer"&gt;Stylex&lt;/a&gt;, you could write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;stylex&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@stylexjs/stylex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// styles&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stylex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;lineHeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Toggle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// interactions&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setToggle&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setToggle&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// markup&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;stylex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;props&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;toggle&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can be a fan or not of writing CSS in object notation (I’m not), but this level of co-location is often a good way to make a component-based project more maintainable: everything is within reach and explicitly bound.&lt;/p&gt;

&lt;p&gt;In libraries like Svelte, the co-location is even more clear (and the code more concise):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;toggle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;$state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onclick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;toggle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;toggle&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;'button'&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="na"&gt;onclick&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    {toggle}
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;line-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Over time, this pattern has gained so much traction to the point that everything is encapsulated in components. You have probably encountered page components like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="na"&gt;nav&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Nav&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Stack&lt;/span&gt; &lt;span class="na"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Item 1&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Item 2&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Item 3&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Stack&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Footer&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Co-location of one
&lt;/h2&gt;

&lt;p&gt;The above code looks clean and consistent: we use the component interface to describe a page.&lt;/p&gt;

&lt;p&gt;But then, let’s look at the possible implementation of &lt;code&gt;Stack&lt;/code&gt;. This component is usually a wrapper to ensure all direct child elements are vertically stacked and evenly spaced:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;stylex&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@stylexjs/stylex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PropsWithChildren&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stylex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;flexDirection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;column&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;rowGap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Stack&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;spacing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;PropsWithChildren&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;stylex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;props&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We only define the styles and the root element of the component. &lt;/p&gt;

&lt;p&gt;In this case, we could even say that &lt;strong&gt;the only thing we are co-locating is the style block&lt;/strong&gt; since the HTML is only used to hold a CSS class reference, and there is no interactivity or business logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  The (avoidable) cost of flexibility
&lt;/h2&gt;

&lt;p&gt;Now, what if we want to be able to render the root element as a &lt;code&gt;section&lt;/code&gt; and maybe add some attributes? We need to enter the realm of polymorphic components. In React and with TypeScript this might end up being something like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;stylex&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@stylexjs/stylex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PolymorphicComponentProps&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ElementType&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;children&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ComponentPropsWithoutRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stylex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;flexDirection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;column&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;rowGap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Stack&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ElementType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;spacing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;
&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;PolymorphicComponentProps&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Component&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;stylex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;props&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In my opinion, this isn't very readable at first glance. And remember: we are just rendering an element with 3 CSS declarations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Back to the basics
&lt;/h2&gt;

&lt;p&gt;A while back, I was working on a pet project in Angular. Being used to thinking in components, I reached out to them to create a &lt;code&gt;Stack&lt;/code&gt;. It turns out that in Angular polymorphic components are &lt;a href="https://www.angularspace.com/bringing-polymorphic-functional-components-to-angular-with-signal-inputs-2/" rel="noopener noreferrer"&gt;even more complex to create&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;I started to question my implementation design and then I had an epiphany: why spend time and lines of code on complex implementations when the solution had been right in front of me all along?&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;row-gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Really, that’s the barebone &lt;em&gt;native&lt;/em&gt; implementation of the &lt;code&gt;Stack&lt;/code&gt; . Once you load the CSS in the layout, it can be used right away in your code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="na"&gt;nav&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Nav&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"stack"&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"--s: 2"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Item 1&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Item 2&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Item 3&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Footer&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's see the main advantages of this approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reusability&lt;/li&gt;
&lt;li&gt;reduced complexity&lt;/li&gt;
&lt;li&gt;smaller JavaScript bundle and less overhead&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;interoperability&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last point is easy to overlook: Not every project uses React, and if you’re including the stack layout pattern in a Design System or a redistributable UI library, developers could use it in projects using different UI frameworks or a server-side language like PHP or Ruby.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nice features and improvements
&lt;/h2&gt;

&lt;p&gt;From this base, you can iterate to add more features and improve the developer experience. While some of the following examples target React specifically, they can be easily adapted to other frameworks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Control spacing
&lt;/h3&gt;

&lt;p&gt;If you're developing a component library you definitely want to define a set of pre-defined spacing variants to make space more consistent. This approach also eliminates the need to explicitly write the style attribute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="nc"&gt;.stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;--s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="na"&gt;row-gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nc"&gt;.s&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nd"&gt;:1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;--s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nc"&gt;.s&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nd"&gt;:2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;--s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nc"&gt;.s&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nd"&gt;:4&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;--s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nc"&gt;.s&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nd"&gt;:6&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;--s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/** Usage:
&amp;lt;div class="stack s:2"&amp;gt;
&amp;lt;/div&amp;gt;
*/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a bolder approach to spacing, see &lt;a href="https://complementary.space/" rel="noopener noreferrer"&gt;Complementary Space&lt;/a&gt; by Donnie D'Amato.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add better scoping
&lt;/h3&gt;

&lt;p&gt;Scoping, in this case, refers to techniques to prevent conflicts with other styles using the same selector. I’d argue that scoping issues affects a pretty small number of projects, but if you are really concerned about it, you could:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use something as simple as &lt;a href="https://github.com/css-modules/css-modules" rel="noopener noreferrer"&gt;CSS Modules&lt;/a&gt;, which is well supported in all major bundlers and frontend frameworks.&lt;/li&gt;
&lt;li&gt;Use &lt;a href="https://knowler.dev/blog/so-you-want-to-encapsulate-your-styles#using-cascade-layers-to-isolate-our-styles" rel="noopener noreferrer"&gt;cascade layers resets&lt;/a&gt; to prevent external stylesheets from modifying your styles (this is an interesting technique).&lt;/li&gt;
&lt;li&gt;Define a specific namespace like &lt;code&gt;.my-app-...&lt;/code&gt; for your classes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is the result with CSS Modules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="nc"&gt;.stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;--s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="na"&gt;row-gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nc"&gt;.s1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;--s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nc"&gt;.s2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;--s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nc"&gt;.s4&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;--s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nc"&gt;.s6&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;--s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/** Usage
import * from './styles/stack.module.css'

&amp;lt;div className={`${styles.stack} ${styles.s2}`}&amp;gt;
    // ...
&amp;lt;/div&amp;gt;  
*/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add type-safety in JavaScript frameworks
&lt;/h3&gt;

&lt;p&gt;The CSS-only solution provides neither typing nor IDE auto-completion. &lt;/p&gt;

&lt;p&gt;Also, if we are not using spacing variants, it might feel too verbose to write both a &lt;code&gt;class&lt;/code&gt; and a &lt;code&gt;style&lt;/code&gt; attribute instead of a &lt;code&gt;spacing&lt;/code&gt; prop. Assuming you're using React, you could leverage JSX and create a utility function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;spacing&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stack&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--s&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;spacing&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CSSProperties&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/* Usage:
&amp;lt;div {...stack({ spacing: 2 })}&amp;gt;
    // ...
&amp;lt;/div&amp;gt;  
*/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that React TypeScript doesn’t allow unknown CSS properties. I used a type assertion for brevity, but you should choose a &lt;a href="https://8hob.io/posts/type-css-variables-react/" rel="noopener noreferrer"&gt;more robust solution&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you’re using variants you can modify the utility function to provide a developer experience similar to &lt;a href="https://panda-css.com/docs/concepts/patterns#stack" rel="noopener noreferrer"&gt;PandaCSS patterns&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;spacing&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`stack s:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/* Usage:
&amp;lt;div className={stack({ spacing: 2 })}&amp;gt;
    // ...
&amp;lt;/div&amp;gt;  
*/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Prevent code duplication and hardcoded values
&lt;/h3&gt;

&lt;p&gt;Some of you might have noticed that, in the last example, I hardcoded the expected values of &lt;code&gt;spacing&lt;/code&gt; in both the CSS and the utility files. If a value is removed or added, this might be an issue because we must keep the two files in sync. &lt;/p&gt;

&lt;p&gt;If you’re building a library, automated visual regression tests will probably catch this kind of issue. Anyway, if it still bothers you, a solution might be to reach for CSS Modules and either use &lt;a href="https://blog.logrocket.com/write-type-safe-css-modules/" rel="noopener noreferrer"&gt;typed-css-modules&lt;/a&gt; or throw a runtime error for unsupported values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="nc"&gt;.stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;--s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="na"&gt;row-gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nc"&gt;.s&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nd"&gt;:1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;--s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nc"&gt;.s&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nd"&gt;:2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;--s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nc"&gt;.s&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nd"&gt;:4&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;--s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nc"&gt;.s&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nd"&gt;:6&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;--s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./stack.module.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;spacing&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;modifier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;s:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;modifier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Spacing value not supported: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;modifier&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Alternatives
&lt;/h2&gt;

&lt;p&gt;If you still think a polymorphic component would be better, really can't deal with plain HTML, or don’t want to write CSS in a separate file (though I am not sure why), my next suggestion would be to take a look at &lt;a href="https://panda-css.com/" rel="noopener noreferrer"&gt;PandaCSS&lt;/a&gt; and create custom patterns or explore other options like &lt;a href="https://vanilla-extract.style/" rel="noopener noreferrer"&gt;vanilla-extract&lt;/a&gt;. In my opinion, these tools are an over-engineered CSS metalanguage but still better than a polymorphic component.&lt;/p&gt;

&lt;p&gt;Another alternative worth considering is &lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;Tailwind CSS&lt;/a&gt;, which has &lt;strong&gt;the advantage of being interoperable between languages and frameworks&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Using the default &lt;a href="https://tailwindcss.com/docs/customizing-spacing#default-spacing-scale" rel="noopener noreferrer"&gt;spacing scale&lt;/a&gt; defined by Tailwind, we could create a &lt;code&gt;stack-&lt;/code&gt; plugin like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;plugin&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tailwindcss/plugin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="cm"&gt;/** @type {import('tailwindcss').Config} */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;plugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;matchComponents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// dynamic component&lt;/span&gt;
        &lt;span class="c1"&gt;// will match stack-0, stack-1, stack-4, ... &lt;/span&gt;
      &lt;span class="nf"&gt;matchComponents&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stack&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;flex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;flexDirection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;column&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;rowGap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;spacing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/* Usage:
&amp;lt;div className="stack-2"&amp;gt;
    // ...
&amp;lt;/div&amp;gt;  
*/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As a side note: it's interesting that Tailwind uses the component mental model in &lt;code&gt;matchComponents&lt;/code&gt; to describe complex CSS rulesets, even if it does not create any &lt;em&gt;real&lt;/em&gt; component. Maybe another example of how pervasive the concept is?  &lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;p&gt;The case of &lt;em&gt;Componentitis&lt;/em&gt;, beyond its technical aspects, demonstrates the importance of pausing to examine and question our mental models and habits. Like many patterns in software development, components emerged as solutions to real problems, but when we began defaulting to this pattern, it became a silent source of complexity. &lt;em&gt;Componentitis&lt;/em&gt; resembles those nutritional deficiencies caused by a restricted diet: the problem isn't with any single food but rather with missing out on everything else.&lt;/p&gt;

</description>
      <category>ui</category>
      <category>css</category>
    </item>
  </channel>
</rss>
