<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Werkbank</title>
    <link href="https://werkbank.dev/atom.xml" rel="self"/>
    <link href="https:&#x2F;&#x2F;werkbank.dev"/>
    <updated>2026-01-20T18:07:20+0100</updated>
    <id>https:&#x2F;&#x2F;werkbank.dev</id>

    
    
    
    
        
    
    
    
        
        
            
            <entry>
                <title>Building a Resizable Grid</title>
                <link href="https:&#x2F;&#x2F;werkbank.dev&#x2F;blog&#x2F;building-resizable-grid&#x2F;"/>
                <updated>2026-01-18T00:00:00+0000</updated>
                <id>https:&#x2F;&#x2F;werkbank.dev&#x2F;blog&#x2F;building-resizable-grid&#x2F;</id>
                <content type="html">&amp;lt;p class=&amp;quot;typl8-drop-cap&amp;quot;&amp;gt;It starts with a layout. It always starts with a layout. &amp;quot;I want an IDE,&amp;quot; I tell myself. &amp;quot;I want something that feels like Sublime Text. I want a sidebar. I want a terminal at the bottom. I want a main editor area. And I want to resize them all.&amp;quot; I want to build rich user interfaces that feel like *applications*, not websites.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;So I look at the tools. &amp;lt;code&amp;gt;react-resizable-panels&amp;lt;&amp;#x2F;code&amp;gt; is great, but it&amp;#x27;s 1-dimensional. To get a grid, you have to nest panels inside panels. You have a Row, and inside that Row, you have two Columns. And inside one of those Columns, you have another Row. It&amp;#x27;s a tree. But I don&amp;#x27;t want a tree. I want a grid. And then I try to use it on my tablet. I try to grab that 6px wide border with my thumb. I fail. I try again. I fail. Why is this so hard?&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;I look at &amp;lt;code&amp;gt;react-grid-layout&amp;lt;&amp;#x2F;code&amp;gt;. It&amp;#x27;s powerful. But it feels like a dashboard. It wants me to drag widgets around. It wants to manage &amp;quot;items.&amp;quot; I just want to move a line. I just want to say &amp;quot;this column is now wider.&amp;quot;&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;I realized I was fighting the abstractions. I was trying to force a tree structure to behave like a grid, or a dashboard engine to behave like a layout engine.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;the-epiphany-css-grid-is-already-the-answer&amp;quot;&amp;gt;The Epiphany: CSS Grid is Already the Answer&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;I stopped looking at React libraries and looked at CSS.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;grid-template-columns: 200px 1fr 300px;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;grid-template-rows: 1fr 200px;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;&amp;#x2F;ul&amp;gt;
&amp;lt;p&amp;gt;That&amp;#x27;s it. That&amp;#x27;s the API I want. CSS Grid already solves the layout problem perfectly. It handles the alignment, the spacing, the responsiveness. All I need is a way to change those numbers when I drag a mouse.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;And what is a drag? It&amp;#x27;s not state. It&amp;#x27;s not a value. It&amp;#x27;s a stream. It&amp;#x27;s &amp;lt;code&amp;gt;pointerdown&amp;lt;&amp;#x2F;code&amp;gt;. Then a flurry of &amp;lt;code&amp;gt;pointermove&amp;lt;&amp;#x2F;code&amp;gt; events. Then &amp;lt;code&amp;gt;pointerup&amp;lt;&amp;#x2F;code&amp;gt;. It&amp;#x27;s a sequence of events over time. And when you say &amp;quot;sequence of events over time,&amp;quot; there is only one tool that should come to mind. RxJS.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;how-it-works-the-architecture&amp;quot;&amp;gt;How it Works: The Architecture&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;I decided to build a single component. No nested providers. No recursive structures. Just one &amp;lt;code&amp;gt;&amp;amp;lt;ResizeableGrid &amp;#x2F;&amp;amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;. But how do you resize a grid gap? You can&amp;#x27;t catch events on a gap. So I cheated. I injected columns.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; utils.ts&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;export let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; getGridTemplateColumns&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; (&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;	groups&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; Columns&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;	handleSize&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; string&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;1rem&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;	let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; lastIndex&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; groups&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;length&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; -&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; 1&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;	return&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; groups&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;		.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;map&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;g&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt; index&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;			&amp;#x2F;&amp;#x2F; [Content] [Handle] [Content]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;			return&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; `&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;${&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;getLength&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;g&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;size&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;} ${&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;lastIndex&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; !==&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; index&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; ?&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; handleSize&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; :&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;`&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;		}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;		.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;join&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot; &amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;};&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;My grid isn&amp;#x27;t just content. It&amp;#x27;s content interleaved with &amp;quot;handles.&amp;quot; If I have 3 columns of content, I actually have 5 columns in the CSS Grid.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;Column 1. Handle 1. Column 2. Handle 2. Column 3.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;the-invisible-skeleton&amp;quot;&amp;gt;The Invisible Skeleton&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;There was a problem. If I defined a 3x3 grid, but only put one item in the top-left corner, the rest of the grid collapsed. CSS Grid tries to be smart. It shrinks empty tracks. But I needed the grid to be rigid. I needed it to exist even if it was empty. So I filled it with ghosts.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;tsx&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; grid.tsx&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; areas&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; useMemo&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;	return&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; Array&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(columns&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; *&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; rows)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;		.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;fill&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E78284;&amp;quot;&amp;gt;null&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;		.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;map&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;_&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt; arrayindex&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;			&amp;#x2F;&amp;#x2F; ... calculate row and column ...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;			return&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; (&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;				&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;div&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt;					key&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;gridArea&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt;					className&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;`row-&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;${&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;row&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; col-&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;${&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;column&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;`&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt;					style&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; gridArea&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; width&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;100%&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; height&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;100%&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; }}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;				&amp;#x2F;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;			)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;		}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;},&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; [columns&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; rows])&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;I generate a &amp;lt;code&amp;gt;div&amp;lt;&amp;#x2F;code&amp;gt; for every single cell in the grid. These divs are invisible. They have no content. But they force the grid to respect the &amp;lt;code&amp;gt;grid-template-rows&amp;lt;&amp;#x2F;code&amp;gt; and &amp;lt;code&amp;gt;grid-template-columns&amp;lt;&amp;#x2F;code&amp;gt; I defined. They hold the structure open so the resize handles have somewhere to live.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;&amp;quot;But wait,&amp;quot; I hear you ask. &amp;quot;Doesn&amp;#x27;t that create a lot of DOM nodes?&amp;quot; Yes, it does. But for an application layout, we are talking about maybe 12 to 20 divs max. We aren&amp;#x27;t rendering a data grid with 10,000 rows. We are rendering the skeleton of the page. The cost is negligible compared to the stability it buys us.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;the-fat-finger-problem&amp;quot;&amp;gt;The &amp;quot;Fat Finger&amp;quot; Problem&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;Speaking of handles, have you ever tried to grab a 6px border on a touch screen? It&amp;#x27;s miserable. I wanted a thin, elegant line. But I wanted a big, chunky hit area. CSS to the rescue again.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; grid.css.ts&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;export let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; dragHandelButton&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; style&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;	&amp;#x2F;&amp;#x2F; ...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;	position&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;absolute&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;	width&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;100%&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;	height&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;100%&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;    &amp;#x2F;&amp;#x2F; ...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;export let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; dragHandelButtonVariant&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; styleVariants&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;	vertical&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; [&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;		dragHandelButton&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;		{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;			cursor&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;ew-resize&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;			paddingLeft&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;0.5rem&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;			paddingRight&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;0.5rem&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;			left&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;-0.5rem&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt; &amp;#x2F;&amp;#x2F; Center the padding over the line&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;		},&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;	]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;    &amp;#x2F;&amp;#x2F; ...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;The button is transparent. It has &amp;lt;code&amp;gt;0.5rem&amp;lt;&amp;#x2F;code&amp;gt; padding on both sides. It&amp;#x27;s positioned negatively so that the padding centers exactly over the visible line. To the eye, it&amp;#x27;s a pixel. To the finger, it&amp;#x27;s a highway.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;accessibility-not-just-for-mouse-users&amp;quot;&amp;gt;Accessibility: Not Just for Mouse Users&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;But what if you can&amp;#x27;t use a mouse? What if you can&amp;#x27;t use a touchscreen? A resize handle is an interactive element. It must be focusable. It must be operable with a keyboard. I made each handle a &amp;lt;code&amp;gt;&amp;amp;lt;button&amp;amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;tsx&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; dragHandle.tsx&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;button&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;    {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;props&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt;    tabIndex&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt;0&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt;    onKeyDown&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;handleKeyDown&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;    &amp;#x2F;&amp;#x2F; ...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;#x2F;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;And I implemented the arrow keys.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; dragHandle.tsx&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; handleKeyDown&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; KeyboardEventHandler&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt;HTMLElement&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; (&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;event&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;    if&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; (&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;!&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;[&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;ArrowLeft&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;ArrowRight&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;ArrowUp&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;ArrowDown&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;includes&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(event&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;key))&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;        return&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;    }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;    let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; movementX&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; event&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;key&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; ===&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;ArrowLeft&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; ? -&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt;8&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; :&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; event&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;key&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; ===&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;ArrowRight&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; ?&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; 8&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; :&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; 0&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;    &amp;#x2F;&amp;#x2F; ...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    &amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;    onResize&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; movementX&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; ...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;};&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;If you tab to a vertical handle, you can use Left&amp;#x2F;Right arrows to move it by 8px. If you tab to a horizontal handle, you can use Up&amp;#x2F;Down. It uses the exact same &amp;lt;code&amp;gt;onResize&amp;lt;&amp;#x2F;code&amp;gt; stream as the mouse interaction.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;This isn&amp;#x27;t just &amp;quot;nice to have.&amp;quot; It&amp;#x27;s essential. If your tool is for developers, you have to assume some of them are power users who hate leaving the keyboard.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;the-missing-piece-usedrag&amp;quot;&amp;gt;The Missing Piece: useDrag&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;I keep mentioning &amp;quot;the stream,&amp;quot; but where does it come from? I built a hook called &amp;lt;code&amp;gt;useDrag&amp;lt;&amp;#x2F;code&amp;gt;. Its job is to normalize the chaos of browser events. We use &amp;lt;strong&amp;gt;Pointer Events&amp;lt;&amp;#x2F;strong&amp;gt;. They are the modern standard that unifies mouse, touch, and pen interactions into a single API. &amp;lt;code&amp;gt;useDrag&amp;lt;&amp;#x2F;code&amp;gt; abstracts this away.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; useDrag.ts (Conceptual)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;export function&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; useDrag&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;() {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;    &amp;#x2F;&amp;#x2F; ...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;    &amp;#x2F;&amp;#x2F; Listen for pointer events&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;    let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; move$&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; fromEvent&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(document&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;pointermove&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    &amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;    &amp;#x2F;&amp;#x2F; Calculate deltas&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;    return&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; move$&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;pipe&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;        map&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;event&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; (&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;            movementX&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; event&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;movementX&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;            &amp;#x2F;&amp;#x2F; ...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;        }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;))&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    )&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;It returns a &amp;lt;code&amp;gt;drag$&amp;lt;&amp;#x2F;code&amp;gt; observable that emits clean, normalized &amp;lt;code&amp;gt;{ movementX, movementY }&amp;lt;&amp;#x2F;code&amp;gt; objects. The grid component doesn&amp;#x27;t care if you are using a mouse, a trackpad, or an Apple Pencil. It just consumes the delta.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;the-unit-problem-pixels-vs-fractions&amp;quot;&amp;gt;The Unit Problem: Pixels vs. Fractions&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;One of the trickiest parts of building a grid is units. CSS Grid loves &amp;lt;code&amp;gt;fr&amp;lt;&amp;#x2F;code&amp;gt; (fraction) units. &amp;lt;code&amp;gt;1fr 2fr&amp;lt;&amp;#x2F;code&amp;gt; means the second column is twice as wide as the first. But pointer events are in pixels. You drag &amp;lt;code&amp;gt;10px&amp;lt;&amp;#x2F;code&amp;gt; to the right. If you try to mix them, you go insane. &amp;quot;Add 10px to 1fr.&amp;quot; What does that even mean?&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;So I normalize everything. When a drag starts, I read the &amp;lt;em&amp;gt;current computed pixel width&amp;lt;&amp;#x2F;em&amp;gt; of the columns. I do all the math in pixels. &amp;lt;code&amp;gt;200px + 10px = 210px&amp;lt;&amp;#x2F;code&amp;gt;. But then, before I save the state, I convert it back to relative units.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; utils.ts&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;export function&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; toPercent&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;sizePx&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; number&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt; parent&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; HTMLElement&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt; orientation&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;font-style: italic;&amp;quot;&amp;gt;vertical&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; |&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;font-style: italic;&amp;quot;&amp;gt;horizontal&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;) {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;	let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; parentSize&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; orientation&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; ===&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;vertical&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; ?&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; parent&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;clientWidth&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; :&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; parent&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;clientHeight&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;	return&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; `&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;${&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;sizePx&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; &amp;#x2F;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; parentSize&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; *&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; 100&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;fr`&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;};&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;Why &amp;lt;code&amp;gt;fr&amp;lt;&amp;#x2F;code&amp;gt; and not &amp;lt;code&amp;gt;%&amp;lt;&amp;#x2F;code&amp;gt;? Because &amp;lt;code&amp;gt;fr&amp;lt;&amp;#x2F;code&amp;gt; handles the &amp;quot;available space&amp;quot; better when you have fixed-size tracks mixed in. By converting the pixel result into a fraction of the container, the grid remains responsive. If you resize the window, the columns scale proportionally.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;collapsing-panels&amp;quot;&amp;gt;Collapsing Panels&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;&amp;quot;But what if I want to hide the sidebar?&amp;quot; In an IDE, you often want to collapse a panel completely. My grid supports this natively via constraints.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; grid.stories.tsx&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;defaultValue&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    columns&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; [&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;        {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; size&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; 200&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; minSize&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; 0&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; maxSize&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; 500&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; },&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt; &amp;#x2F;&amp;#x2F; Sidebar&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;        &amp;amp;quot;1fr&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt; &amp;#x2F;&amp;#x2F; Main content&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    ]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;If you drag the sidebar to the left, it shrinks. If you hit 0px, it vanishes. Because we are using CSS Grid, &amp;lt;code&amp;gt;0fr&amp;lt;&amp;#x2F;code&amp;gt; or &amp;lt;code&amp;gt;0px&amp;lt;&amp;#x2F;code&amp;gt; effectively hides the column. The content inside is still there (so state is preserved), but it takes up no space.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;persistence-remembering-the-state&amp;quot;&amp;gt;Persistence: Remembering the State&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;There is nothing more annoying than an IDE that forgets your layout when you refresh the page. Because I&amp;#x27;m using RxJS, I can tap into the state stream easily.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; grid.tsx&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; [&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;gridState&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; setGridState&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; useGridState&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    defaultColumns&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; [&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;auto&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;auto&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;auto&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    defaultRows&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; [&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;auto&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;auto&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    persist&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;my-grid-layout&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt; &amp;#x2F;&amp;#x2F; Auto-save to localStorage&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;I built a custom hook &amp;lt;code&amp;gt;useGridState&amp;lt;&amp;#x2F;code&amp;gt; that wraps the RxJS behavior subject. It has built-in persistence. When the &amp;lt;code&amp;gt;gridState&amp;lt;&amp;#x2F;code&amp;gt; updates (which happens on &amp;lt;code&amp;gt;mouseup&amp;lt;&amp;#x2F;code&amp;gt;), it automatically writes to &amp;lt;code&amp;gt;localStorage&amp;lt;&amp;#x2F;code&amp;gt;. When the component mounts, it rehydrates from storage. It&amp;#x27;s one line of code, but it makes the grid feel &amp;quot;pro.&amp;quot;&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;the-api-controlled-vs-uncontrolled&amp;quot;&amp;gt;The API: Controlled vs Uncontrolled&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;One of the biggest challenges in building reusable components is deciding who owns the state. Should the component manage itself? Or should the parent control it? I decided to follow the Web Platform.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;Just like a native &amp;lt;code&amp;gt;&amp;amp;lt;input&amp;amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;, the grid supports both modes. You can let it manage itself (Uncontrolled) or you can take the wheel (Controlled). It feels familiar because it mirrors the API you&amp;#x27;ve been using since HTML 1.0.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Uncontrolled Mode&amp;lt;&amp;#x2F;strong&amp;gt; is great for simple layouts where you just want it to work. You give it a &amp;lt;code&amp;gt;defaultValue&amp;lt;&amp;#x2F;code&amp;gt;, and it handles the rest. This follows the same philosophy as our &amp;lt;a href=&amp;quot;&amp;#x2F;blog&amp;#x2F;building-custom-react-inputs&amp;#x2F;&amp;quot;&amp;gt;Building Custom React Inputs&amp;lt;&amp;#x2F;a&amp;gt; approach: let the component manage its own state when possible.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;tsx&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #F4B8E4;&amp;quot;&amp;gt;ResizeableGrid&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt;    persist&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;my-layout&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt;    defaultValue&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;        columns&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; [&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt;200&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;1fr&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;, {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; size&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; 200&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; minSize&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; 100&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; maxSize&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; 300&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;        rows&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; [&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;auto&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;auto&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;    }}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;    &amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #F4B8E4;&amp;quot;&amp;gt;GridArea&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt; column&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; start&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; 1&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; end&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; 2&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; }}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt; row&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; start&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; 1&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; end&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; 2&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; }}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;        Sidebar&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;    &amp;amp;lt;&amp;#x2F;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #F4B8E4;&amp;quot;&amp;gt;GridArea&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;    {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;* ... *&amp;#x2F;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;lt;&amp;#x2F;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #F4B8E4;&amp;quot;&amp;gt;ResizeableGrid&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Controlled Mode&amp;lt;&amp;#x2F;strong&amp;gt; is for when you need full power. Maybe you want a button that toggles the sidebar. Maybe you want to save the layout to a database instead of localStorage.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;tsx&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; [&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;state&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; setState&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; useGridState&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    columns&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; 3&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    rows&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; 2&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    defaultColumns&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; [&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; size&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; 200&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; mode&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;static&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; },&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;1fr&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;auto&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    defaultRows&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; [&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;auto&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; 200&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; toggleSidebar&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; ()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;    setState&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;current&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;        &amp;#x2F;&amp;#x2F; ... logic to toggle column size ...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;    }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;return&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; (&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;    &amp;amp;lt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;        &amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;button&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt; onClick&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;toggleSidebar&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;Toggle Sidebar&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;lt;&amp;#x2F;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;button&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;        &amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #F4B8E4;&amp;quot;&amp;gt;ResizeableGrid&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt;            value&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;state&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt;            onChange&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;setState&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;        &amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;             {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;* ... *&amp;#x2F;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;        &amp;amp;lt;&amp;#x2F;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #F4B8E4;&amp;quot;&amp;gt;ResizeableGrid&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;    &amp;amp;lt;&amp;#x2F;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;By exposing both &amp;lt;code&amp;gt;value&amp;lt;&amp;#x2F;code&amp;gt;&amp;#x2F;&amp;lt;code&amp;gt;onChange&amp;lt;&amp;#x2F;code&amp;gt; and &amp;lt;code&amp;gt;defaultValue&amp;lt;&amp;#x2F;code&amp;gt;, we get the flexibility of a controlled component with the ease of use of an uncontrolled one.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;is-rxjs-overkill&amp;quot;&amp;gt;Is RxJS Overkill?&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;I know what you&amp;#x27;re thinking. &amp;quot;You imported the entire RxJS library just to drag a div?&amp;quot; First, RxJS is tree-shakeable. I&amp;#x27;m only importing &amp;lt;code&amp;gt;merge&amp;lt;&amp;#x2F;code&amp;gt;, &amp;lt;code&amp;gt;map&amp;lt;&amp;#x2F;code&amp;gt;, &amp;lt;code&amp;gt;share&amp;lt;&amp;#x2F;code&amp;gt;, &amp;lt;code&amp;gt;tap&amp;lt;&amp;#x2F;code&amp;gt;, and &amp;lt;code&amp;gt;sample&amp;lt;&amp;#x2F;code&amp;gt;. Second, try writing this in vanilla JS.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;You need &amp;lt;code&amp;gt;pointerdown&amp;lt;&amp;#x2F;code&amp;gt; handlers. You need &amp;lt;code&amp;gt;pointermove&amp;lt;&amp;#x2F;code&amp;gt; handlers attached to &amp;lt;code&amp;gt;document&amp;lt;&amp;#x2F;code&amp;gt; (so you don&amp;#x27;t lose the drag if the mouse moves fast). You need &amp;lt;code&amp;gt;keydown&amp;lt;&amp;#x2F;code&amp;gt; handlers for accessibility. You need to clean them all up when the component unmounts. You need to throttle the updates to 60fps.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;With RxJS, I just say: &amp;lt;code&amp;gt;merge(pointer$, key$).pipe(...)&amp;lt;&amp;#x2F;code&amp;gt; It&amp;#x27;s declarative. It handles the cleanup. It handles the race conditions. It&amp;#x27;s not overkill; it&amp;#x27;s the right tool for the job.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;the-stream-rxjs-in-action&amp;quot;&amp;gt;The Stream: RxJS in Action&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;Now for the engine. I didn&amp;#x27;t want to manage &amp;lt;code&amp;gt;isDragging&amp;lt;&amp;#x2F;code&amp;gt; state in React. I didn&amp;#x27;t want to trigger re-renders 60 times a second just to update a width. I wanted to bypass React entirely during the drag.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; grid.tsx&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;useEffect&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;    &amp;#x2F;&amp;#x2F; ...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;    let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; dragEvent$&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; merge&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(drag$&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; resize$)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;pipe&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;share&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;())&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;    let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; xSubscription&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; dragEvent$&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;pipe&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;onDrag&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;col&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;))&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;subscribe&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;columns&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;        setColumns&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(columns)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;    }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    &amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;    let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; ySubscription&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; dragEvent$&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;pipe&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;onDrag&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;row&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;))&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;subscribe&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;rows&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;        setRows&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(rows)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;    }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;    return&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; ()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;        xSubscription&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;unsubscribe&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;        ySubscription&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;unsubscribe&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;    };&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;},&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; ...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;Wait, &amp;lt;code&amp;gt;setColumns&amp;lt;&amp;#x2F;code&amp;gt;? That triggers a re-render! Yes, but look at &amp;lt;code&amp;gt;onDrag&amp;lt;&amp;#x2F;code&amp;gt;. Inside the &amp;lt;code&amp;gt;onDrag&amp;lt;&amp;#x2F;code&amp;gt; operator pipeline, I do something unconventional. I talk directly to the DOM.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; grid.tsx&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;tap&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;next&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;    if&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; (type&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; ===&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;col&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;        parent&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;style&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;gridTemplateColumns&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; getGridTemplateColumns&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;            next&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;            dragHandleSize&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;        )&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;    }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;    &amp;#x2F;&amp;#x2F; ...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;sample&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(dragEnd$)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt; &amp;#x2F;&amp;#x2F; Only emit to React when the drag stops!&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;I update the &amp;lt;code&amp;gt;style&amp;lt;&amp;#x2F;code&amp;gt; property of the grid container directly in the stream. The browser repaints instantly. React knows nothing about it.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;Only when the user lifts their mouse (&amp;lt;code&amp;gt;sample(dragEnd$)&amp;lt;&amp;#x2F;code&amp;gt;) do I let the value pass through to &amp;lt;code&amp;gt;setColumns&amp;lt;&amp;#x2F;code&amp;gt;. React wakes up, sees the new state, and reconciles. But by then, the heavy lifting is done.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;the-safety-valve&amp;quot;&amp;gt;The Safety Valve&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;&amp;quot;But isn&amp;#x27;t direct DOM manipulation dangerous?&amp;quot; It can be. If you modify the DOM and then React tries to modify it, you get conflicts. But here, React owns the &amp;lt;em&amp;gt;structure&amp;lt;&amp;#x2F;em&amp;gt; (the divs), and I only touch the &amp;lt;em&amp;gt;style&amp;lt;&amp;#x2F;em&amp;gt; of the container.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;Also, notice the cleanup in &amp;lt;code&amp;gt;useEffect&amp;lt;&amp;#x2F;code&amp;gt;. When the component unmounts, &amp;lt;code&amp;gt;xSubscription.unsubscribe()&amp;lt;&amp;#x2F;code&amp;gt; is called. This kills the stream. Even if a drag event is pending, it won&amp;#x27;t fire. We are safe.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;the-logic-push-and-pull&amp;quot;&amp;gt;The Logic: Push and Pull&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;Resizing a grid is a zero-sum game. If I make the sidebar wider, the main content must get narrower. I can&amp;#x27;t just change one number. I have to steal from &amp;lt;strong&amp;gt;Han&amp;lt;&amp;#x2F;strong&amp;gt; to pay &amp;lt;strong&amp;gt;Chewie&amp;lt;&amp;#x2F;strong&amp;gt;.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; utils.ts&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;function&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; applyConstrained&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;) {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;    let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; total&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; currentEntry&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;size&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; +&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; nextEntry&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;size&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;    &amp;#x2F;&amp;#x2F; Clamp current&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    currentEntry&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;size&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; clamp&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(currentEntry&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;size&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; current&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;min&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; current&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;max)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;    &amp;#x2F;&amp;#x2F; Adjust next&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    nextEntry&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;size&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; total&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; -&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; currentEntry&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;size&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;    &amp;#x2F;&amp;#x2F; Clamp next&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    nextEntry&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;size&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; clamp&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(nextEntry&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;size&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; next&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;min&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; next&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;max)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;    &amp;#x2F;&amp;#x2F; Adjust current again (in case next hit a constraint)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    currentEntry&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;size&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; total&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; -&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; nextEntry&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;size&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;It&amp;#x27;s a dance. I push right. The current column grows. The next column shrinks. But wait! The next column has a &amp;lt;code&amp;gt;minSize&amp;lt;&amp;#x2F;code&amp;gt; of &amp;lt;code&amp;gt;200px&amp;lt;&amp;#x2F;code&amp;gt;. It refuses to shrink further. So I have to stop growing the current column.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;This logic happens in the stream, on every frame. It feels solid. It feels physical.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;conclusion&amp;quot;&amp;gt;Conclusion&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;I could have used a library. I could have accepted the nested divs. I could have lived with the bad touch support. But sometimes, you just want the thing to feel right.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;I wanted a grid. So I used CSS Grid.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;I wanted a stream of events. So I used RxJS.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;I wanted it to be fast. So I bypassed React for the hot path.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;&amp;#x2F;ul&amp;gt;
&amp;lt;p&amp;gt;It’s not a generic &amp;quot;Dashboard Builder.&amp;quot; It’s not a &amp;quot;Panel Manager.&amp;quot; It’s just a grid. And it resizes.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;This is just the beginning. With this foundation, we can build anything. Collapsible sidebars, tabbed interfaces, complex data grids. The primitives are there. The performance is there. The only limit is the layout you can imagine.&amp;lt;&amp;#x2F;p&amp;gt;
</content>
            </entry>
            
        
            
            <entry>
                <title>TypeScript Meta-programming and Proxies</title>
                <link href="https:&#x2F;&#x2F;werkbank.dev&#x2F;blog&#x2F;typescript-meta-programming-and-proxies&#x2F;"/>
                <updated>2026-01-17T00:00:00+0000</updated>
                <id>https:&#x2F;&#x2F;werkbank.dev&#x2F;blog&#x2F;typescript-meta-programming-and-proxies&#x2F;</id>
                <content type="html">&amp;lt;p class=&amp;quot;typl8-drop-cap&amp;quot;&amp;gt;We all want our code to read like a sentence. There is a certain beauty in an API that just flows, where the intent is obvious and the boilerplate is non-existent.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;In languages like Rust, we have powerful tools to achieve this. We have Macros. Macros allow us to write code that writes other code at compile time. It&amp;#x27;s meta-programming in its truest sense. You can define a &amp;lt;code&amp;gt;derive&amp;lt;&amp;#x2F;code&amp;gt; macro and suddenly your struct has JSON serialization, database mapping, and a CLI interface, all without you writing a single extra line of logic.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;rust&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; In Rust, this one line generates a ton of code for us&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt;#&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;[&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt;derive&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt;Debug&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; Serialize&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; Deserialize&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;)]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;struct&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; User&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    id&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; u32&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    name&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; String&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;But we aren&amp;#x27;t in Rust. We are in TypeScript. And TypeScript, for all its structural typing glory, does not have macros. We can&amp;#x27;t hook into the compilation process to generate code on the fly (well, not easily). So when we want to build complex abstractions, we often find ourselves stuck between two bad options: writing verbose boilerplate or setting up fragile code-generation scripts.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;But JavaScript gives us something else. It gives us a different kind of superpower. It gives us &amp;lt;strong&amp;gt;Proxies&amp;lt;&amp;#x2F;strong&amp;gt;.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h2 id=&amp;quot;enter-the-proxy&amp;quot;&amp;gt;Enter the Proxy&amp;lt;&amp;#x2F;h2&amp;gt;
&amp;lt;p&amp;gt;If you haven&amp;#x27;t used a &amp;lt;a rel=&amp;quot;external&amp;quot; href=&amp;quot;https:&amp;#x2F;&amp;#x2F;developer.mozilla.org&amp;#x2F;en-US&amp;#x2F;docs&amp;#x2F;Web&amp;#x2F;JavaScript&amp;#x2F;Reference&amp;#x2F;Global_Objects&amp;#x2F;Proxy&amp;quot;&amp;gt;Proxy&amp;lt;&amp;#x2F;a&amp;gt; before, it&amp;#x27;s exactly what it sounds like. It&amp;#x27;s a wrapper around an object that intercepts operations. You can intercept a property read, a function call, an assignment—pretty much anything.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;It allows for what I like to call &amp;quot;Runtime Meta-programming.&amp;quot; Instead of generating code at compile time, we can define behavior for properties that don&amp;#x27;t even exist yet. We can make an object that replies &amp;quot;Yes!&amp;quot; to any question you ask it, or an array that logs every time you try to touch its elements.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;Now, I can hear the performance purists sharpening their pitchforks. &amp;quot;Proxies are slow! Runtime interception is expensive!&amp;quot; And you&amp;#x27;re right. Compared to a raw property access, a Proxy is slower. But we have to ask: what are we optimizing for? In many cases, especially when dealing with I&amp;#x2F;O, network requests, or IPC (Inter-Process Communication), the bottleneck is not the property access. It&amp;#x27;s the operation itself. The microsecond cost of a Proxy is negligible compared to the millisecond latency of a network round-trip.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;For the developer experience (DX) gains? It&amp;#x27;s often a trade worth making.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h2 id=&amp;quot;the-problem-a-magic-rpc-client&amp;quot;&amp;gt;The Problem: A Magic RPC Client&amp;lt;&amp;#x2F;h2&amp;gt;
&amp;lt;p&amp;gt;I ran into this while building the RPC system for Werkbank. I wanted to communicate between the main thread and a Web Worker. Usually, this involves a lot of &amp;lt;code&amp;gt;postMessage&amp;lt;&amp;#x2F;code&amp;gt; calls and event listeners. It&amp;#x27;s messy, it&amp;#x27;s verbose, and it breaks the flow we desire. Most importantly, it&amp;#x27;s not type-safe. I wanted an API that felt local. I wanted to be able to write this:&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; I want this to call the worker, wait for the result, and return it.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;const&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; user&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; await&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; client&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;users&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;getUser&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt;123&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;But I didn&amp;#x27;t want to manually write a &amp;lt;code&amp;gt;getUser&amp;lt;&amp;#x2F;code&amp;gt; method on the client for every single function in my worker. That&amp;#x27;s the boilerplate trap. And I didn&amp;#x27;t want to run a script to generate a client file every time I changed the worker code. That&amp;#x27;s the code-gen trap.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;I wanted it to just work. I wanted the client to magically know that &amp;lt;code&amp;gt;client.users.getUser&amp;lt;&amp;#x2F;code&amp;gt; maps to a specific function in the worker, without me ever explicitly defining it.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h2 id=&amp;quot;the-solution-recursive-proxies&amp;quot;&amp;gt;The Solution: Recursive Proxies&amp;lt;&amp;#x2F;h2&amp;gt;
&amp;lt;p&amp;gt;This is where the Proxy shines. We can create a &amp;quot;Recursive Proxy&amp;quot;—a proxy that, when you access a property on it, returns &amp;lt;em&amp;gt;another&amp;lt;&amp;#x2F;em&amp;gt; proxy.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;Here is the core of the implementation from &amp;lt;code&amp;gt;werkbank&amp;#x2F;src&amp;#x2F;rpc&amp;#x2F;client&amp;#x2F;proxy.ts&amp;lt;&amp;#x2F;code&amp;gt;. I&amp;#x27;ve simplified it slightly for clarity, but the recursive structure is the real deal.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;Note: I&amp;#x27;m using RxJS here for handling the event streams because it makes filtering, mapping, timeouts, and &amp;lt;strong&amp;gt;cancellation&amp;lt;&amp;#x2F;strong&amp;gt; easier.&amp;lt;&amp;#x2F;em&amp;gt;&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;export function&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; createRpcProxy&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt;Config&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;	postMessage&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; PostMessage&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;	incoming$&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; Observable&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt;Event&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;unknown&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; RpcClient&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt;Config&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;    &amp;#x2F;&amp;#x2F; We keep a cache of proxies to avoid creating new ones for the same path repeatedly.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;    &amp;#x2F;&amp;#x2F; This helps with memory and ensures object identity stability for the same path.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;	let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; proxies&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;font-weight: bold;&amp;quot;&amp;gt; new&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; Map&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;string&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; any&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;	function&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; createProxyHandler&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;scope&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; Array&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;string&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; []&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;) {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;		let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; handler&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; ProxyHandler&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;any&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;			get&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;_target&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt; prop&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;) {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;				let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; key&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; prop&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;toString&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;                &amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;                &amp;#x2F;&amp;#x2F; Important: Don&amp;amp;#39;t proxy &amp;amp;#39;then&amp;amp;#39; if you don&amp;amp;#39;t want the proxy itself to be awaitable.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;                &amp;#x2F;&amp;#x2F; In our case, only the function call returns a Promise.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;                if&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; (key&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; ===&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;#39;then&amp;amp;#39;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; return undefined&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;				let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; proxyPath&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; [&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;scope&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; key]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;join&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;.&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;                &amp;#x2F;&amp;#x2F; Return cached proxy if it exists&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;				let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; currentProxy&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; proxies&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;get&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(proxyPath)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;				if&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; (currentProxy)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;					return&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; currentProxy&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;				}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;                &amp;#x2F;&amp;#x2F; This is the function that will eventually be called&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;                &amp;#x2F;&amp;#x2F; e.g. client.users.getUser(123)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;				let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; fn&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; ProxyFn&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; (&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;rawArgs&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; Array&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;unknown&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;					let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; id&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; crypto&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;randomUUID&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt; &amp;#x2F;&amp;#x2F; Use standard UUID generation&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;                    &amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;                    &amp;#x2F;&amp;#x2F; We automatically scan arguments for Transferable objects (like ArrayBuffers)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;                    &amp;#x2F;&amp;#x2F; to ensure zero-copy transfer to the worker. This traverses the args recursively.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;					let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; args&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; transfer&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; extractTransferables&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(rawArgs)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;                    &amp;#x2F;&amp;#x2F; Send the request to the worker&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;					postMessage&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;						REQUEST&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;							id&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;							args&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;							path&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; [&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;scope&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; key]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt; &amp;#x2F;&amp;#x2F; e.g. [&amp;amp;#39;users&amp;amp;#39;, &amp;amp;#39;getUser&amp;amp;#39;]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;						}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;						transfer&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;					)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;                    &amp;#x2F;&amp;#x2F; ... logic to wait for the response (we&amp;amp;#39;ll get to this) ...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;				}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;				&amp;#x2F;&amp;#x2F; Return a new Proxy for the next level of the chain&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;                &amp;#x2F;&amp;#x2F; We wrap &amp;amp;#39;fn&amp;amp;#39; so that if the user calls it, our &amp;amp;#39;fn&amp;amp;#39; executes.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;                &amp;#x2F;&amp;#x2F; If they access a property on it, the &amp;amp;#39;get&amp;amp;#39; trap fires again.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;				let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; proxy&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;font-weight: bold;&amp;quot;&amp;gt; new&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; Proxy&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(fn&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; createProxyHandler&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;([&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;scope&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; key]))&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;				proxies&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;set&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(proxyPath&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; proxy)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;				return&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; proxy&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;			}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;		}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;		return&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; handler&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;	}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;    &amp;#x2F;&amp;#x2F; We cast the result to RpcClient&amp;amp;lt;Config&amp;amp;gt; to make TypeScript happy.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;    &amp;#x2F;&amp;#x2F; The runtime object is just a Proxy, but we promise the compiler it behaves like Config.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;	return&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;font-weight: bold;&amp;quot;&amp;gt; new&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; Proxy&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{},&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; createProxyHandler&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;([]))&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; as&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; RpcClient&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt;Config&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;Let&amp;#x27;s break down what happens when we call &amp;lt;code&amp;gt;client.users.getUser(123)&amp;lt;&amp;#x2F;code&amp;gt;:&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;ol&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;&amp;lt;code&amp;gt;client.users&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;strong&amp;gt;: The first proxy intercepts the &amp;lt;code&amp;gt;get&amp;lt;&amp;#x2F;code&amp;gt; for &amp;quot;users&amp;quot;. It doesn&amp;#x27;t find it on the target object (which is empty), so it returns a &amp;lt;em&amp;gt;new&amp;lt;&amp;#x2F;em&amp;gt; Proxy, remembering the path &amp;lt;code&amp;gt;[&amp;#x27;users&amp;#x27;]&amp;lt;&amp;#x2F;code&amp;gt;.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;&amp;lt;code&amp;gt;.getUser&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;strong&amp;gt;: That new proxy intercepts the &amp;lt;code&amp;gt;get&amp;lt;&amp;#x2F;code&amp;gt; for &amp;quot;getUser&amp;quot;. It returns &amp;lt;em&amp;gt;another&amp;lt;&amp;#x2F;em&amp;gt; new Proxy, now with the path &amp;lt;code&amp;gt;[&amp;#x27;users&amp;#x27;, &amp;#x27;getUser&amp;#x27;]&amp;lt;&amp;#x2F;code&amp;gt;.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;&amp;lt;code&amp;gt;(123)&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;strong&amp;gt;: Finally, we call the function. The proxy wraps our &amp;lt;code&amp;gt;fn&amp;lt;&amp;#x2F;code&amp;gt;, so we can intercept the call. Inside that function, we take the accumulated path (&amp;lt;code&amp;gt;[&amp;#x27;users&amp;#x27;, &amp;#x27;getUser&amp;#x27;]&amp;lt;&amp;#x2F;code&amp;gt;) and the arguments (&amp;lt;code&amp;gt;[123]&amp;lt;&amp;#x2F;code&amp;gt;), and we fire off a &amp;lt;code&amp;gt;postMessage&amp;lt;&amp;#x2F;code&amp;gt;.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;&amp;#x2F;ol&amp;gt;
&amp;lt;h3 id=&amp;quot;bridging-the-gap-from-postmessage-to-promise&amp;quot;&amp;gt;Bridging the Gap: From &amp;lt;code&amp;gt;postMessage&amp;lt;&amp;#x2F;code&amp;gt; to Promise&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;The trickiest part of any RPC system is mapping the asynchronous response back to the original request. &amp;lt;code&amp;gt;postMessage&amp;lt;&amp;#x2F;code&amp;gt; is fire-and-forget. It returns &amp;lt;code&amp;gt;void&amp;lt;&amp;#x2F;code&amp;gt;. But our client function needs to return a &amp;lt;code&amp;gt;Promise&amp;lt;&amp;#x2F;code&amp;gt;.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;We solve this with a unique ID and RxJS streams. One of the huge benefits of using RxJS here is how easily we can add robustness, like timeouts and &amp;lt;strong&amp;gt;cancellation&amp;lt;&amp;#x2F;strong&amp;gt;.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; Inside the &amp;amp;#39;fn&amp;amp;#39; above...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; response$&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; incoming$&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;pipe&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;    &amp;#x2F;&amp;#x2F; Only listen for a REPLY matching our specific request ID&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;    filter&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;e&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; REPLY&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;match&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(e)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; &amp;amp;amp;&amp;amp;amp;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; e&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;payload&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;id&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; ===&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; id)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;    take&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt;1&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt; &amp;#x2F;&amp;#x2F; We only expect one response&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    &amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;    &amp;#x2F;&amp;#x2F; Add a timeout! If the worker doesn&amp;amp;#39;t reply in 5s, fail.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;    timeout&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt;5000&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; &amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    &amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;    map&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;e&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;        if&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; (e&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;payload&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;reject)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;            throw&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; e&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;payload&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;reject&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;        }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;        return&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; e&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;payload&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;resolve&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;    }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;    &amp;#x2F;&amp;#x2F; If the consumer unsubscribes (e.g. React useEffect cleanup),&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;    &amp;#x2F;&amp;#x2F; we tell the worker to cancel the task.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;    finalize&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;        postMessage&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;UNSUBSCRIBE&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; id&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; [])&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;    }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; Convert the Observable to a Promise so the user can &amp;amp;#39;await&amp;amp;#39; it&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;return&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; firstValueFrom&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(response$)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;This effectively pauses the execution on the main thread (via &amp;lt;code&amp;gt;await&amp;lt;&amp;#x2F;code&amp;gt;) until the worker processes the task and sends back a message with the matching ID, or until the timeout fires.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h2 id=&amp;quot;but-is-it-type-safe&amp;quot;&amp;gt;But is it Type Safe?&amp;lt;&amp;#x2F;h2&amp;gt;
&amp;lt;p&amp;gt;I promised type safety. And this is where TypeScript&amp;#x27;s generics come in. Notice the &amp;lt;code&amp;gt;&amp;amp;lt;Config&amp;amp;gt;&amp;lt;&amp;#x2F;code&amp;gt; generic in &amp;lt;code&amp;gt;createRpcProxy&amp;amp;lt;Config&amp;amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;We can define our worker&amp;#x27;s API as a standard TypeScript interface. Note that on the worker side, these functions might return direct values, but on the client side, we need them to be Promises.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;We achieve this with a recursive mapped type. We use &amp;lt;code&amp;gt;Awaited&amp;amp;lt;R&amp;amp;gt;&amp;lt;&amp;#x2F;code&amp;gt; to ensure we don&amp;#x27;t accidentally create &amp;lt;code&amp;gt;Promise&amp;amp;lt;Promise&amp;amp;lt;T&amp;amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;code&amp;gt; if the worker function is already async.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; Recursively traverse the type T.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; If it&amp;amp;#39;s a function, wrap the return type in a Promise.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; If it&amp;amp;#39;s an object, recurse into it.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;type&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; Promisify&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt;T&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt;    [K&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; in keyof&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; T]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; T[K]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; extends&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; (&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;args&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; infer&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; A&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; infer&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; R&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;        ?&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; (&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;args&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; A&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; Promise&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt;Awaited&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt;R&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;        :&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; Promisify&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt;T[K]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;};&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; Define the shape of your worker API&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;interface&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; WorkerApi&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    users&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;        getUser&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;id&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; number&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; User&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt; &amp;#x2F;&amp;#x2F; Worker returns User synchronously&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;        createUser&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;name&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; string&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; User&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;    };&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; The RpcClient type magically wraps everything in Promises&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;const&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; client&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; createRpcProxy&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt;WorkerApi&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(postMessage&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; incoming$)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; Now client.users.getUser returns Promise&amp;amp;lt;User&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;const&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; user&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; await&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; client&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;users&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;getUser&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt;123&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;Now, when you type &amp;lt;code&amp;gt;client.&amp;lt;&amp;#x2F;code&amp;gt;, TypeScript knows exactly what properties exist. It knows &amp;lt;code&amp;gt;client.users&amp;lt;&amp;#x2F;code&amp;gt; exists. It knows &amp;lt;code&amp;gt;client.users.getUser&amp;lt;&amp;#x2F;code&amp;gt; takes a &amp;lt;code&amp;gt;number&amp;lt;&amp;#x2F;code&amp;gt; and returns a &amp;lt;code&amp;gt;Promise&amp;amp;lt;User&amp;amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;If you try to type &amp;lt;code&amp;gt;client.users.deleteUser(123)&amp;lt;&amp;#x2F;code&amp;gt;, TypeScript will yell at you. Even though the &amp;lt;em&amp;gt;runtime&amp;lt;&amp;#x2F;em&amp;gt; proxy would happily accept that call and send a message to the worker (which would then fail), the &amp;lt;em&amp;gt;compiler&amp;lt;&amp;#x2F;em&amp;gt; stops you before you even run the code.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h2 id=&amp;quot;trade-offs&amp;quot;&amp;gt;Trade-offs&amp;lt;&amp;#x2F;h2&amp;gt;
&amp;lt;p&amp;gt;No solution is perfect, and Proxies are no exception. Here is what you are trading:&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Pros:&amp;lt;&amp;#x2F;strong&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Zero Boilerplate:&amp;lt;&amp;#x2F;strong&amp;gt; No manual client definitions.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Type Safety:&amp;lt;&amp;#x2F;strong&amp;gt; Full TypeScript support with generics.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Refactoring Safety:&amp;lt;&amp;#x2F;strong&amp;gt; Renaming a method in the worker interface immediately flags errors in the client code.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Flexibility:&amp;lt;&amp;#x2F;strong&amp;gt; The API can evolve on the worker side without breaking the client (as long as types match).&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;&amp;#x2F;ul&amp;gt;
&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Cons:&amp;lt;&amp;#x2F;strong&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Runtime Overhead:&amp;lt;&amp;#x2F;strong&amp;gt; Proxies are slower than direct property access (though usually negligible for RPC).&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Debugging:&amp;lt;&amp;#x2F;strong&amp;gt; &amp;lt;code&amp;gt;console.log(client)&amp;lt;&amp;#x2F;code&amp;gt; just shows a Proxy object, which can be confusing.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Browser Support:&amp;lt;&amp;#x2F;strong&amp;gt; Proxies cannot be polyfilled. They are supported in all modern browsers, but if you need to support very old environments, this won&amp;#x27;t work.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;&amp;#x2F;ul&amp;gt;
&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;&amp;#x2F;ul&amp;gt;
&amp;lt;h2 id=&amp;quot;conclusion&amp;quot;&amp;gt;Conclusion&amp;lt;&amp;#x2F;h2&amp;gt;
&amp;lt;p&amp;gt;We might not have macros in TypeScript, but we have something that fits the dynamic nature of JavaScript perfectly. Proxies allow us to build &amp;quot;Magic&amp;quot; APIs—interfaces that adapt and respond to how we use them, rather than how they were defined. They bridge the gap between the static world of types and the dynamic world of runtime execution. And sometimes, that&amp;#x27;s even better than a macro.&amp;lt;&amp;#x2F;p&amp;gt;
</content>
            </entry>
            
        
            
            <entry>
                <title>Beyond the Main Thread</title>
                <link href="https:&#x2F;&#x2F;werkbank.dev&#x2F;blog&#x2F;beyond-the-main-thread&#x2F;"/>
                <updated>2026-01-16T00:00:00+0000</updated>
                <id>https:&#x2F;&#x2F;werkbank.dev&#x2F;blog&#x2F;beyond-the-main-thread&#x2F;</id>
                <content type="html">&amp;lt;p class=&amp;quot;typl8-drop-cap&amp;quot;&amp;gt;I am typing this and the cursor blinks. It blinks because the main thread is free. But for how long?&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;We are building apps that are too big for the browser. Not &amp;quot;big&amp;quot; like &amp;quot;lots of HTML&amp;quot;. Big like &amp;quot;video editor&amp;quot;, &amp;quot;IDE&amp;quot;, &amp;quot;database&amp;quot;. We are parsing syntax trees. We are processing audio buffers. We are running SQL queries against a WASM Postgres instance. And every time we do one of those things, the cursor stops blinking.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;You paste 10,000 lines of JSON into a text area. The frame drops. The scroll stutters. The user sighs. We know the solution. It’s been there since 2009. &amp;lt;strong&amp;gt;Web Workers&amp;lt;&amp;#x2F;strong&amp;gt;. The browser is multi-threaded! We can spawn threads! We can run code in parallel! We can have our cake and eat it too!&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;So why aren&amp;#x27;t we doing it?&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h2 id=&amp;quot;the-postmessage-problem&amp;quot;&amp;gt;The postMessage Problem&amp;lt;&amp;#x2F;h2&amp;gt;
&amp;lt;p&amp;gt;Because &amp;lt;code&amp;gt;postMessage&amp;lt;&amp;#x2F;code&amp;gt; is awful. It is the assembly language of the web. It&amp;#x27;s like sending smoke signals in binary. You send a message. Maybe it’s a string. Maybe it’s an object. You lose your prototypes. You lose your functions. You lose your types. And then you wait.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;You add an event listener. &amp;lt;code&amp;gt;onmessage&amp;lt;&amp;#x2F;code&amp;gt;. You get an event. &amp;lt;code&amp;gt;e.data&amp;lt;&amp;#x2F;code&amp;gt;. What is &amp;lt;code&amp;gt;data&amp;lt;&amp;#x2F;code&amp;gt;? Who knows. It’s &amp;lt;code&amp;gt;any&amp;lt;&amp;#x2F;code&amp;gt;. You have to invent a protocol. &amp;quot;Okay, I&amp;#x27;ll send &amp;lt;code&amp;gt;{ type: &amp;#x27;REQUEST&amp;#x27;, id: 1, payload: ... }&amp;lt;&amp;#x2F;code&amp;gt;&amp;quot;. And the worker will send back &amp;lt;code&amp;gt;{ type: &amp;#x27;RESPONSE&amp;#x27;, id: 1, payload: ... }&amp;lt;&amp;#x2F;code&amp;gt;.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;Now you have to match the IDs. You have to manage the state. You have to handle errors. What if the worker throws? The error doesn&amp;#x27;t cross the boundary. It just dies silently in the console.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;It is friction. It is mental overhead. It is enough to make you say, &amp;quot;I&amp;#x27;ll just put it in a &amp;lt;code&amp;gt;useEffect&amp;lt;&amp;#x2F;code&amp;gt; and hope nobody notices the jank.&amp;quot;&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h2 id=&amp;quot;the-dream-of-the-invisible-worker&amp;quot;&amp;gt;The Dream of the Invisible Worker&amp;lt;&amp;#x2F;h2&amp;gt;
&amp;lt;p&amp;gt;I don&amp;#x27;t want to think about workers. I don&amp;#x27;t want to think about serialization. I want to call a function.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; I want this&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;const&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; result&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; await&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; api&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;heavyComputation&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(data)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;I want to interact with a stateful system. I want to increment counters, update documents, and subscribe to real-time streams of events.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; I want to call methods on nested modules&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;await&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; api&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;Counter&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;inc&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt;1&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; I want to subscribe to streams&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;api&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;seconds&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;subscribe&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;tick&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;  console&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;log&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(tick)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;&amp;lt;h2 id=&amp;quot;enter-werkbank-rpc&amp;quot;&amp;gt;Enter werkbank&amp;#x2F;rpc&amp;lt;&amp;#x2F;h2&amp;gt;
&amp;lt;p&amp;gt;So I built it. It is a bridge. A transparent, type-safe bridge between the main thread and the worker. It starts with a Proxy. When you create a client, we give you a ghost. It looks like your API. It has the same methods. It has the same types. But it is hollow. When you call a method on this ghost, it intercepts the call. It packages the arguments. It generates a UUID. It sends a &amp;lt;code&amp;gt;REQUEST&amp;lt;&amp;#x2F;code&amp;gt; message to the worker.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;And then it waits. But it doesn&amp;#x27;t just wait for a promise. It waits for an &amp;lt;em&amp;gt;Observable&amp;lt;&amp;#x2F;em&amp;gt;.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h2 id=&amp;quot;why-rxjs&amp;quot;&amp;gt;Why RxJS?&amp;lt;&amp;#x2F;h2&amp;gt;
&amp;lt;p&amp;gt;In most RPC libraries, everything is a Promise. &amp;lt;code&amp;gt;async&amp;#x2F;await&amp;lt;&amp;#x2F;code&amp;gt;. You ask a question, you get an answer. But sometimes, a function isn&amp;#x27;t just a question. Sometimes it&amp;#x27;s a conversation.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;Imagine a file upload. You don&amp;#x27;t just want to know when it&amp;#x27;s done. You want to know the progress. &amp;quot;10%... 20%... 50%...&amp;quot;. A Promise can&amp;#x27;t do that. A Promise resolves once. But an &amp;lt;strong&amp;gt;Observable&amp;lt;&amp;#x2F;strong&amp;gt; can emit many values over time.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;With &amp;lt;code&amp;gt;werkbank&amp;#x2F;rpc&amp;lt;&amp;#x2F;code&amp;gt;, if your worker function returns an Observable, the client receives an Observable. You can subscribe to progress updates, real-time data feeds, or log streams.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;And the best part? &amp;lt;strong&amp;gt;Cancellation is free.&amp;lt;&amp;#x2F;strong&amp;gt; One of the biggest pain points with Promises is that you can&amp;#x27;t cancel them. If the user navigates away while a heavy calculation is running, that calculation keeps running. It eats CPU. It drains battery.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;But you &amp;lt;em&amp;gt;can&amp;lt;&amp;#x2F;em&amp;gt; unsubscribe from an Observable.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; React Component Example&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;useEffect&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;  const&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; sub&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; api&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;search&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(query)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;subscribe&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;results&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;    setResults&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(results)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;  }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;  &amp;#x2F;&amp;#x2F; Cleanup function: runs when component unmounts or query changes&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;  return&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; ()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; sub&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;unsubscribe&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; &amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;},&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; [query])&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;When you unsubscribe on the main thread, we send an &amp;lt;code&amp;gt;UNSUBSCRIBE&amp;lt;&amp;#x2F;code&amp;gt; signal to the worker. The worker tears down the operation instantly. No more zombie computations.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h2 id=&amp;quot;the-best-of-both-worlds&amp;quot;&amp;gt;The Best of Both Worlds&amp;lt;&amp;#x2F;h2&amp;gt;
&amp;lt;p&amp;gt;&amp;quot;But I don&amp;#x27;t want to use RxJS for everything!&amp;quot; I hear you. Sometimes you just want &amp;lt;code&amp;gt;await&amp;lt;&amp;#x2F;code&amp;gt;. So I built a hybrid.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;function&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; observablePromise&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;observable&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt; promise&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;) {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;    let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; hybrid&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; observable&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; as any&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    hybrid&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;then&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; promise&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;then&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;bind&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(promise)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt; &amp;#x2F;&amp;#x2F; It acts like a Promise&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;    return&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; hybrid&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;You can &amp;lt;code&amp;gt;await&amp;lt;&amp;#x2F;code&amp;gt; it. You can &amp;lt;code&amp;gt;.subscribe()&amp;lt;&amp;#x2F;code&amp;gt; to it. It adapts to you.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Note:&amp;lt;&amp;#x2F;strong&amp;gt; This is pragmatic magic. &amp;quot;Thenables&amp;quot; are a known pattern in JS, and mixing them with Observables gives us the best of both worlds. You get the simplicity of &amp;lt;code&amp;gt;await&amp;lt;&amp;#x2F;code&amp;gt; for single values, and the power of RxJS for streams, without changing your API surface.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h2 id=&amp;quot;the-cost-of-serialization&amp;quot;&amp;gt;The Cost of Serialization&amp;lt;&amp;#x2F;h2&amp;gt;
&amp;lt;p&amp;gt;Speaking of performance, let&amp;#x27;s talk about the elephant in the room. &amp;quot;But wait,&amp;quot; I hear you say. &amp;quot;What about serialization? Isn&amp;#x27;t &amp;lt;code&amp;gt;postMessage&amp;lt;&amp;#x2F;code&amp;gt; slow?&amp;quot; Yes, it can be. If you send a 10MB JSON object, the browser has to clone it. That takes time.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;But &amp;lt;code&amp;gt;werkbank&amp;#x2F;rpc&amp;lt;&amp;#x2F;code&amp;gt; doesn&amp;#x27;t solve this by magic. It solves it by letting you use &amp;lt;strong&amp;gt;Transferables&amp;lt;&amp;#x2F;strong&amp;gt;. If you pass an &amp;lt;code&amp;gt;ArrayBuffer&amp;lt;&amp;#x2F;code&amp;gt;, we transfer it. Zero copy. Instant.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;And for everything else? The cost of cloning a few kilobytes is measured in microseconds. The cost of blocking the main thread for 50ms is measured in user frustration.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;I will take the serialization cost over the jank any day.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h2 id=&amp;quot;shared-workers-yes&amp;quot;&amp;gt;Shared Workers? Yes.&amp;lt;&amp;#x2F;h2&amp;gt;
&amp;lt;p&amp;gt;We didn&amp;#x27;t stop at dedicated workers. We also support &amp;lt;strong&amp;gt;SharedWorkers&amp;lt;&amp;#x2F;strong&amp;gt;. Why? Because if you have 10 tabs open, you don&amp;#x27;t want 10 database connections. You want one. &amp;lt;code&amp;gt;werkbank&amp;#x2F;rpc&amp;lt;&amp;#x2F;code&amp;gt; detects if you are connecting to a SharedWorker and handles the port negotiation automatically. The API remains exactly the same. You just change &amp;lt;code&amp;gt;new Worker()&amp;lt;&amp;#x2F;code&amp;gt; to &amp;lt;code&amp;gt;new SharedWorker()&amp;lt;&amp;#x2F;code&amp;gt;.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;This is huge for things like local-first apps. You can run a full SQL database (like PGlite) in a SharedWorker. If you ran that on the main thread, every query would freeze the UI. In a worker, it&amp;#x27;s seamless. Your UI just subscribes to the queries.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h2 id=&amp;quot;the-worker-side&amp;quot;&amp;gt;The Worker Side&amp;lt;&amp;#x2F;h2&amp;gt;
&amp;lt;p&amp;gt;Okay, the client is magic. But what about the worker? Is it a mess of boilerplate? No. It is just code.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; worker.ts&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;import&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; interval&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; from&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;rxjs&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; count&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; 0&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;const&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; api&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;  &amp;#x2F;&amp;#x2F; Nested modules? No problem.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;  Counter&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;    inc&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;val&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; number&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;) {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; count&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; +=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; val&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;; },&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;    get&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;() {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; return&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; count&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;; }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;  },&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;  &amp;#x2F;&amp;#x2F; Streaming function&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;  seconds&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;() {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;    return&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; interval&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt;1000&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;pipe&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;map&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;i&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; `Tick &amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;${&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;i&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;`&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;))&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;  }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;};&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;createWorker&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; mod&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; api&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;That&amp;#x27;s it. No message handlers. No switch statements. Just functions. The &amp;lt;code&amp;gt;createWorker&amp;lt;&amp;#x2F;code&amp;gt; function wraps your API. It listens for those &amp;lt;code&amp;gt;REQUEST&amp;lt;&amp;#x2F;code&amp;gt; messages. It finds the right function. It runs it.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;If it throws, we catch it. We serialize the error. We send it back. The client promise rejects. The &amp;lt;code&amp;gt;try&amp;#x2F;catch&amp;lt;&amp;#x2F;code&amp;gt; block on the main thread works exactly as you expect.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h2 id=&amp;quot;type-safety-the-secret-sauce&amp;quot;&amp;gt;Type Safety (The Secret Sauce)&amp;lt;&amp;#x2F;h2&amp;gt;
&amp;lt;p&amp;gt;But the real magic is the types. We use TypeScript&amp;#x27;s mapped types to project the worker&amp;#x27;s types onto the client. It acts like a mirror.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; packages&amp;#x2F;werkbank&amp;#x2F;src&amp;#x2F;rpc&amp;#x2F;client&amp;#x2F;index.ts&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;type&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; RpcClient&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt;Config&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt;    [Key&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; in keyof&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; Config]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; Config[Key]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; extends&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; (&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;args&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; any&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt;[]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; any&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;    ?&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; Fn&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt;Parameters&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt;Config[Key]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; ReturnType&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt;Config[Key]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt; &amp;#x2F;&amp;#x2F; It matches!&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;    :&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; RpcClient&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt;Config[Key]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt; &amp;#x2F;&amp;#x2F; It recurses!&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;};&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;This isn&amp;#x27;t just flat mapping. It&amp;#x27;s &amp;lt;strong&amp;gt;recursive&amp;lt;&amp;#x2F;strong&amp;gt;. If your API has nested objects (e.g., &amp;lt;code&amp;gt;api.users.create(...)&amp;lt;&amp;#x2F;code&amp;gt;), the type mapper follows them. It builds a deep proxy structure that mirrors your exact API shape, all the way down.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;The experience is magical. You type &amp;lt;code&amp;gt;api.&amp;lt;&amp;#x2F;code&amp;gt;, and your IDE shows you &amp;lt;code&amp;gt;Counter&amp;lt;&amp;#x2F;code&amp;gt;. You type &amp;lt;code&amp;gt;Counter.&amp;lt;&amp;#x2F;code&amp;gt;, and it shows &amp;lt;code&amp;gt;inc&amp;lt;&amp;#x2F;code&amp;gt;. You hover over &amp;lt;code&amp;gt;inc&amp;lt;&amp;#x2F;code&amp;gt;, and it tells you it expects a &amp;lt;code&amp;gt;number&amp;lt;&amp;#x2F;code&amp;gt;. If I change the &amp;lt;code&amp;gt;add&amp;lt;&amp;#x2F;code&amp;gt; function in the worker to take a string, the client code turns red. Instantly. Across the thread boundary.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h2 id=&amp;quot;conclusion&amp;quot;&amp;gt;Conclusion&amp;lt;&amp;#x2F;h2&amp;gt;
&amp;lt;p&amp;gt;The main thread is for the UI. It is for the user. It is sacred. Everything else—parsing, calculating, searching, filtering—belongs in a worker.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;With &amp;lt;code&amp;gt;werkbank&amp;#x2F;rpc&amp;lt;&amp;#x2F;code&amp;gt;, the barrier is gone. The friction is gone. You can treat the worker as just another module. Just another import.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;Stop blocking the main thread. It&amp;#x27;s rude. Build the app you want to build, not the one the main thread lets you build.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h2 id=&amp;quot;related-post&amp;quot;&amp;gt;Related Post&amp;lt;&amp;#x2F;h2&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;&amp;#x2F;blog&amp;#x2F;typescript-meta-programming-and-proxies&amp;#x2F;&amp;quot;&amp;gt;TypeScript Meta-programming and Proxies&amp;lt;&amp;#x2F;a&amp;gt;&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;&amp;#x2F;ul&amp;gt;
&amp;lt;h2 id=&amp;quot;getting-started&amp;quot;&amp;gt;Getting Started&amp;lt;&amp;#x2F;h2&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a rel=&amp;quot;external&amp;quot; href=&amp;quot;https:&amp;#x2F;&amp;#x2F;docs.werkbank.dev&amp;#x2F;documents&amp;#x2F;Getting_Started.html&amp;quot;&amp;gt;Getting Started&amp;lt;&amp;#x2F;a&amp;gt;&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a rel=&amp;quot;external&amp;quot; href=&amp;quot;https:&amp;#x2F;&amp;#x2F;docs.werkbank.dev&amp;#x2F;documents&amp;#x2F;Getting_Started.Worker_RPC.html&amp;quot;&amp;gt;Worker RPC Guide&amp;lt;&amp;#x2F;a&amp;gt;&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;&amp;#x2F;ul&amp;gt;
&amp;lt;h2 id=&amp;quot;disclaimer&amp;quot;&amp;gt;Disclaimer&amp;lt;&amp;#x2F;h2&amp;gt;
&amp;lt;p&amp;gt;This is a Proof of Concept (PoC). It&amp;#x27;s running in my personal workspace. It&amp;#x27;s not on GitHub yet. It&amp;#x27;s not battle-tested in a million-user app. It&amp;#x27;s an experiment in &amp;quot;What if?&amp;quot;. I plan to open source this properly at a later date, once I&amp;#x27;ve ironed out the kinks and written some actual documentation. But for now, I just wanted to share the idea. Because sometimes, the best way to move forward is to look at what we&amp;#x27;re doing and ask: &amp;quot;Does it have to be this hard?&amp;quot;&amp;lt;&amp;#x2F;p&amp;gt;
</content>
            </entry>
            
        
            
            <entry>
                <title>Building Custom React Inputs</title>
                <link href="https:&#x2F;&#x2F;werkbank.dev&#x2F;blog&#x2F;building-custom-react-inputs&#x2F;"/>
                <updated>2026-01-15T00:00:00+0000</updated>
                <id>https:&#x2F;&#x2F;werkbank.dev&#x2F;blog&#x2F;building-custom-react-inputs&#x2F;</id>
                <content type="html">&amp;lt;p class=&amp;quot;typl8-drop-cap&amp;quot;&amp;gt; It starts with a design. It always starts with a design. &amp;quot;We need a tag selector,&amp;quot; the designer says. &amp;quot;But not a boring select box. We want chips. We want them to animate. We want a little &amp;#x27;x&amp;#x27; button on each one.&amp;quot; So you build it. You create a &amp;lt;code&amp;gt;div&amp;lt;&amp;#x2F;code&amp;gt;. You map over an array of strings. You add some &amp;lt;code&amp;gt;onClick&amp;lt;&amp;#x2F;code&amp;gt; handlers. It looks beautiful. It&amp;#x27;s perfect. Then you try to use it in a form.
&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;tsx&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;form&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt; onSubmit&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;handleSubmit&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;  &amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #F4B8E4;&amp;quot;&amp;gt;ChipsInput&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; &amp;#x2F;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;* The Zombie *&amp;#x2F;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;  &amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;button&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;Submit&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;lt;&amp;#x2F;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;button&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;lt;&amp;#x2F;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;form&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;You hit enter. Nothing happens.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;You try to tab to it. You tab right past it.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;You try to read the &amp;lt;code&amp;gt;FormData&amp;lt;&amp;#x2F;code&amp;gt;. It&amp;#x27;s empty.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;&amp;#x2F;ul&amp;gt;
&amp;lt;p&amp;gt;And suddenly, you realize you&amp;#x27;ve built a zombie. It looks like an input, but it&amp;#x27;s dead inside. It has no soul. It has no &amp;lt;code&amp;gt;value&amp;lt;&amp;#x2F;code&amp;gt;. It has no &amp;lt;code&amp;gt;name&amp;lt;&amp;#x2F;code&amp;gt;.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;Why are we still doing this? We do it because native inputs are notoriously hard to style. You can&amp;#x27;t put a chip &amp;lt;em&amp;gt;inside&amp;lt;&amp;#x2F;em&amp;gt; a text input. You can&amp;#x27;t animate the caret. So we abandon the native element and rebuild the world from scratch with &amp;lt;code&amp;gt;div&amp;lt;&amp;#x2F;code&amp;gt;s.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;I look at the ecosystem. There are a thousand &amp;quot;React Select&amp;quot; libraries. They all have their own state management. They all have their own &amp;lt;code&amp;gt;onChange&amp;lt;&amp;#x2F;code&amp;gt; signature that returns some custom object instead of an event. They all require you to manually wire them up to your form library.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;I didn&amp;#x27;t want a &amp;quot;React Component.&amp;quot; I wanted an &amp;lt;code&amp;gt;input&amp;lt;&amp;#x2F;code&amp;gt;.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;I wanted something that passes the Duck Test. If it walks like a duck, and quacks like a duck, it&amp;#x27;s a native input. Even if it&amp;#x27;s actually three raccoons in a trench coat.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;the-epiphany-the-trojan-horse&amp;quot;&amp;gt;The Epiphany: The Trojan Horse&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;I realized I was fighting the browser. I was trying to re-implement &amp;lt;code&amp;gt;focus&amp;lt;&amp;#x2F;code&amp;gt;, &amp;lt;code&amp;gt;blur&amp;lt;&amp;#x2F;code&amp;gt;, &amp;lt;code&amp;gt;validation&amp;lt;&amp;#x2F;code&amp;gt;, and &amp;lt;code&amp;gt;form submission&amp;lt;&amp;#x2F;code&amp;gt; in JavaScript. Why? The browser already does this. It&amp;#x27;s been doing it for 30 years. So I stopped fighting. I decided to cheat. I decided to build a Trojan Horse. On the outside, it&amp;#x27;s a beautiful, animated, interactive React component. But inside? Deep inside the DOM where the user can&amp;#x27;t see? It&amp;#x27;s just a boring, standard HTML string.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;how-it-works-the-chipsinput&amp;quot;&amp;gt;How it Works: The ChipsInput&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;Let&amp;#x27;s look at the &amp;lt;code&amp;gt;ChipsInput&amp;lt;&amp;#x2F;code&amp;gt;. The goal is to let the user type multiple values, hit enter, and see them appear as &amp;quot;chips.&amp;quot; But to the form, this should just be a comma-separated string. So, I hide the truth.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;tsx&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; 1. The Hidden Messenger&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;input&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt;  aria-hidden&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt;  style&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    position&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;absolute&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    opacity&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; 0&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    pointerEvents&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;none&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    width&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; 0&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    height&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; 0&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;  }}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt;  ref&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;hiddenInputRef&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt;  name&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;name&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt;  value&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;currentValues&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;join&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;,&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt; &amp;#x2F;&amp;#x2F; &amp;amp;quot;react,javascript,css&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt;  onChange&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;validationHandlers&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;onChange&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt;  onBlur&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;validationHandlers&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;onBlur&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt;  required&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;required&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;#x2F;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;This is the soul of the component. It&amp;#x27;s invisible. It takes up no space. But it holds the &amp;lt;code&amp;gt;name&amp;lt;&amp;#x2F;code&amp;gt;. It holds the &amp;lt;code&amp;gt;value&amp;lt;&amp;#x2F;code&amp;gt;. It holds the &amp;lt;code&amp;gt;required&amp;lt;&amp;#x2F;code&amp;gt; attribute. When the form looks for data, it finds this input. When the browser checks for validity, it checks this input.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;syncing-the-state-here-be-dragons&amp;quot;&amp;gt;Syncing the State: Here Be Dragons&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;Now we just need to keep the visual state in sync with this hidden truth.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;When you add a chip, I don&amp;#x27;t just update React state. I update the DOM. But you can&amp;#x27;t just set &amp;lt;code&amp;gt;input.value = &amp;quot;foo&amp;quot;&amp;lt;&amp;#x2F;code&amp;gt;. React tracks the input&amp;#x27;s value internally. If you modify the DOM directly, React&amp;#x27;s internal state gets out of sync with the DOM, and the next render might wipe out your changes.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;We have to be sneaky. We have to bypass React&amp;#x27;s tracker by calling the &amp;lt;em&amp;gt;native&amp;lt;&amp;#x2F;em&amp;gt; value setter from the prototype.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; setChange&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; (&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;values&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; Array&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;string&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;  &amp;#x2F;&amp;#x2F; inputRef points to the hidden &amp;amp;lt;input&amp;amp;gt; element&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;  if&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; (inputRef&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;current)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;    let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; value&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; values&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;join&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(separator)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    &amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;    &amp;#x2F;&amp;#x2F; 2. The Manual Override&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;    &amp;#x2F;&amp;#x2F; We steal the setter from the HTMLInputElement prototype&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;    &amp;#x2F;&amp;#x2F; This allows us to set the value *without* React intercepting it immediately&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;    let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; valueSetter&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; Object&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;getOwnPropertyDescriptor&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;      window&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;HTMLInputElement&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;prototype&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;      &amp;amp;quot;value&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    )&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;?.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;set&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    &amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;    &amp;#x2F;&amp;#x2F; Call the native setter with our DOM node as &amp;amp;#39;this&amp;amp;#39;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    valueSetter&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;?.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;call&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(inputRef&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;current&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; value)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    &amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;    &amp;#x2F;&amp;#x2F; 3. The Fake Event&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;    &amp;#x2F;&amp;#x2F; Dispatch a change event so React (and the world) knows the value changed&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    inputRef&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;current&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;dispatchEvent&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;font-weight: bold;&amp;quot;&amp;gt;new&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; Event&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;change&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;, {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; bubbles&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; true&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;))&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    &amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;    &amp;#x2F;&amp;#x2F; Finally, update our local React state to match&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;    setState&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(values)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;  }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;};&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;I manually set the value on the DOM node using the prototype. This is crucial because it updates the value &amp;lt;em&amp;gt;without&amp;lt;&amp;#x2F;em&amp;gt; React knowing immediately, but then the &amp;lt;code&amp;gt;change&amp;lt;&amp;#x2F;code&amp;gt; event brings everyone back in sync. This tells the world (and any other listeners) that something happened. The form sees the update. The validation logic runs.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;the-forgotten-lifecycle-reset&amp;quot;&amp;gt;The Forgotten Lifecycle: Reset&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;There is one event that React developers almost always forget: &amp;lt;code&amp;gt;reset&amp;lt;&amp;#x2F;code&amp;gt;. When you click &amp;lt;code&amp;gt;&amp;amp;lt;button type=&amp;quot;reset&amp;quot;&amp;amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;, the browser restores all inputs to their &amp;lt;code&amp;gt;defaultValue&amp;lt;&amp;#x2F;code&amp;gt;. But since our &amp;quot;state&amp;quot; is in React &amp;lt;code&amp;gt;useState&amp;lt;&amp;#x2F;code&amp;gt;, the browser&amp;#x27;s reset doesn&amp;#x27;t touch it. The hidden input reverts, but the chips stay on screen.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;The fix? We listen to the form. But we have to wait.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;useEffect&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;  let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; form&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; wrapper&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;current&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;closest&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;form&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;  if&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; (&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;!&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;form)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; return&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;  let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; handleReset&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; ()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;    &amp;#x2F;&amp;#x2F; Wait for the browser to finish its reset&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;    requestAnimationFrame&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;       setState&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;getValues&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(defaultValue))&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;    }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;  };&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;  form&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;addEventListener&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;reset&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; handleReset)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;  return&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; ()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; form&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;removeEventListener&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;reset&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; handleReset)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;},&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; [defaultValue])&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;Why &amp;lt;code&amp;gt;requestAnimationFrame&amp;lt;&amp;#x2F;code&amp;gt;? Because the &amp;lt;code&amp;gt;reset&amp;lt;&amp;#x2F;code&amp;gt; event fires &amp;lt;em&amp;gt;before&amp;lt;&amp;#x2F;em&amp;gt; the browser actually clears the inputs. If we read the value immediately, we&amp;#x27;d get the old value. We have to let the browser finish its work, tick the frame, and &amp;lt;em&amp;gt;then&amp;lt;&amp;#x2F;em&amp;gt; sync our React state to the new reality. (You could use &amp;lt;code&amp;gt;setTimeout(..., 0)&amp;lt;&amp;#x2F;code&amp;gt; here too, but &amp;lt;code&amp;gt;rAF&amp;lt;&amp;#x2F;code&amp;gt; is generally cleaner for visual updates).&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;the-focus-relay-formerly-faking-the-focus&amp;quot;&amp;gt;The Focus Relay (formerly &amp;quot;Faking the Focus&amp;quot;)&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;The hardest part isn&amp;#x27;t the data. It&amp;#x27;s the feel. A native input is a single focusable element. My component is a list of chips, a delete button for each chip, and a text input for adding new ones. If I tab from a chip to the delete button, have I &amp;quot;blurred&amp;quot; the field? Technically, yes. The focus left the container.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;But to the user? No. They are still &amp;quot;in&amp;quot; the input. So we have to fake it. We have to simulate the focus cycle.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; handleInputBlur&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; FocusEventHandler&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt;HTMLInputElement&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; (&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;e&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;  &amp;#x2F;&amp;#x2F; ... logic to check if we moved to another element inside the same wrapper ...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;  &amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;  setInputFocus&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt;false&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;  simulateFocusCycle&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(inputRef&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;current)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;};&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;We wait. We check &amp;lt;code&amp;gt;document.activeElement&amp;lt;&amp;#x2F;code&amp;gt;. If the focus just moved to a neighbor, we do nothing. If it truly left the component, &amp;lt;em&amp;gt;then&amp;lt;&amp;#x2F;em&amp;gt; we fire the &amp;lt;code&amp;gt;onBlur&amp;lt;&amp;#x2F;code&amp;gt; event. But we don&amp;#x27;t just fire a React handler. We go deeper.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;export function&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; simulateFocusCycle&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;elm&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; ValidateElement&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; |&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;font-style: italic;&amp;quot;&amp;gt; null&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;) {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;  if&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; (elm)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    elm&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;dispatchEvent&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;font-weight: bold;&amp;quot;&amp;gt;new&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; Event&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;focusin&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;, {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; bubbles&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; true&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;))&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    elm&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;dispatchEvent&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;font-weight: bold;&amp;quot;&amp;gt;new&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; Event&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;focusout&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;, {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; bubbles&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; true&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;))&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;  }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;We manually dispatch &amp;lt;code&amp;gt;focusin&amp;lt;&amp;#x2F;code&amp;gt; and &amp;lt;code&amp;gt;focusout&amp;lt;&amp;#x2F;code&amp;gt; events on the hidden input. Why? Because validation libraries (and our own code) often listen for these specific events to mark a field as &amp;quot;touched&amp;quot; or to trigger error messages. By manually firing them, we ensure that any external code watching our component sees a valid focus lifecycle, even though the user never actually touched that hidden input.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;the-elephant-in-the-room-accessibility&amp;quot;&amp;gt;The Elephant in the Room: Accessibility&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;&amp;quot;But wait,&amp;quot; I hear you say. &amp;quot;You have an invisible input with &amp;lt;code&amp;gt;aria-hidden&amp;lt;&amp;#x2F;code&amp;gt;. If validation fails, the browser focuses that input. Won&amp;#x27;t the user be lost?&amp;quot;&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;Yes. That is the danger. If the browser focuses an &amp;lt;code&amp;gt;opacity: 0&amp;lt;&amp;#x2F;code&amp;gt; element, the user&amp;#x27;s focus ring disappears. They are tabbed into the void.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;To fix this, we have to listen for the &amp;lt;code&amp;gt;invalid&amp;lt;&amp;#x2F;code&amp;gt; event on the hidden input and manually shift focus back to our &amp;lt;em&amp;gt;visible&amp;lt;&amp;#x2F;em&amp;gt; input.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;hiddenInput&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;addEventListener&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;#39;invalid&amp;amp;#39;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;, (&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;e&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;  e&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;preventDefault&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt; &amp;#x2F;&amp;#x2F; Stop the native browser bubble if it&amp;amp;#39;s confusing&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;  visibleInputRef&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;current&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;?.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;focus&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;  &amp;#x2F;&amp;#x2F; Show our custom error UI&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;It&amp;#x27;s a trade-off. We get the native form behavior, but we have to manage the edge cases where the &amp;quot;native&amp;quot; behavior (focusing the invalid field) conflicts with our &amp;quot;custom&amp;quot; reality (the field is invisible).&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;I chose &amp;lt;code&amp;gt;aria-hidden&amp;lt;&amp;#x2F;code&amp;gt; intentionally. The hidden input is for &amp;lt;em&amp;gt;data&amp;lt;&amp;#x2F;em&amp;gt;, not for &amp;lt;em&amp;gt;humans&amp;lt;&amp;#x2F;em&amp;gt;. The screen reader should interact with the list of chips and the text input, not the comma-separated string in the background. If we didn&amp;#x27;t hide it, the screen reader would announce the field twice: once for the custom UI, and once for the hidden value.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;advanced-moves-the-dateinput&amp;quot;&amp;gt;Advanced Moves: The DateInput&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;This pattern scales. Take a Date Input. Designers love splitting dates: Day, Month, Year. Browsers love ISO strings: &amp;lt;code&amp;gt;YYYY-MM-DD&amp;lt;&amp;#x2F;code&amp;gt;. So we do the same trick, but with a coordinator. We render three visible inputs and one invisible master. But how do they talk to each other? We use React Context to create a mini-state machine.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;ol&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;The Coordinator (&amp;lt;code&amp;gt;DateInput&amp;lt;&amp;#x2F;code&amp;gt;)&amp;lt;&amp;#x2F;strong&amp;gt;: This component holds the single source of truth—the ISO string. It parses this string into &amp;lt;code&amp;gt;day&amp;lt;&amp;#x2F;code&amp;gt;, &amp;lt;code&amp;gt;month&amp;lt;&amp;#x2F;code&amp;gt;, and &amp;lt;code&amp;gt;year&amp;lt;&amp;#x2F;code&amp;gt; integers and exposes them via a Context Provider.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;The Players (&amp;lt;code&amp;gt;Day&amp;lt;&amp;#x2F;code&amp;gt;, &amp;lt;code&amp;gt;Month&amp;lt;&amp;#x2F;code&amp;gt;, &amp;lt;code&amp;gt;Year&amp;lt;&amp;#x2F;code&amp;gt;)&amp;lt;&amp;#x2F;strong&amp;gt;: These are dumb components. They don&amp;#x27;t know about the ISO string. They just consume the Context.
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;&amp;amp;lt;Day &amp;#x2F;&amp;amp;gt;&amp;lt;&amp;#x2F;code&amp;gt; reads &amp;lt;code&amp;gt;ctx.day&amp;lt;&amp;#x2F;code&amp;gt; and calls &amp;lt;code&amp;gt;ctx.setDay(12)&amp;lt;&amp;#x2F;code&amp;gt;.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;&amp;amp;lt;MonthSelect &amp;#x2F;&amp;amp;gt;&amp;lt;&amp;#x2F;code&amp;gt; reads &amp;lt;code&amp;gt;ctx.month&amp;lt;&amp;#x2F;code&amp;gt; and calls &amp;lt;code&amp;gt;ctx.setMonth(1)&amp;lt;&amp;#x2F;code&amp;gt;.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;&amp;#x2F;ul&amp;gt;
&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;The Sync&amp;lt;&amp;#x2F;strong&amp;gt;: When you change the Day, the &amp;lt;code&amp;gt;DateInput&amp;lt;&amp;#x2F;code&amp;gt; intercepts the update.
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;It takes the new Day.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;It combines it with the existing Month and Year.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;It constructs a new ISO string: &amp;lt;code&amp;gt;2024-02-12&amp;lt;&amp;#x2F;code&amp;gt;.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;It updates the hidden &amp;lt;code&amp;gt;&amp;amp;lt;input type=&amp;quot;date&amp;quot; &amp;#x2F;&amp;amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;It dispatches the &amp;lt;code&amp;gt;change&amp;lt;&amp;#x2F;code&amp;gt; event.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;&amp;#x2F;ul&amp;gt;
&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;&amp;#x2F;ol&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;But what about February 31st?&amp;lt;&amp;#x2F;strong&amp;gt;&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;This is where the browser saves us again. If I manually construct the string &amp;lt;code&amp;gt;2024-02-31&amp;lt;&amp;#x2F;code&amp;gt; and set it on the hidden input, the browser&amp;#x27;s native validation kicks in. &amp;lt;code&amp;gt;&amp;amp;lt;input type=&amp;quot;date&amp;quot;&amp;amp;gt;&amp;lt;&amp;#x2F;code&amp;gt; knows that February 31st doesn&amp;#x27;t exist. It marks the field as invalid.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;I don&amp;#x27;t have to write leap year logic. I don&amp;#x27;t have to import &amp;lt;code&amp;gt;date-fns&amp;lt;&amp;#x2F;code&amp;gt; just to check if a day is valid. I just pass the string to the browser, and if the browser rejects it, my CSS &amp;lt;code&amp;gt;:user-invalid&amp;lt;&amp;#x2F;code&amp;gt; styles light up.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;the-mobile-bonus&amp;quot;&amp;gt;The Mobile Bonus&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;There is one more huge benefit to this approach, specifically for the &amp;lt;code&amp;gt;DateInput&amp;lt;&amp;#x2F;code&amp;gt;. If you use a custom JavaScript date picker, you are forcing mobile users to tap tiny little &amp;lt;code&amp;gt;&amp;amp;lt;div&amp;amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;s on a tiny calendar. It&amp;#x27;s miserable. But because we are using &amp;lt;code&amp;gt;&amp;amp;lt;input type=&amp;quot;date&amp;quot;&amp;amp;gt;&amp;lt;&amp;#x2F;code&amp;gt; under the hood, we can choose to expose that to mobile users.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;On desktop, we show our fancy split inputs.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;On mobile, we can show the native date picker.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;&amp;#x2F;ul&amp;gt;
&amp;lt;p&amp;gt;Because the data format is standard (ISO string), we can swap the UI without changing the logic. The browser handles the complex touch interactions, the scrolling pickers, and the localization. We just handle the value.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;the-payoff-styling-with-has&amp;quot;&amp;gt;The Payoff: Styling with :has()&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;I mentioned getting CSS powers for free. This is where it gets fun.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;Because our hidden input is inside our wrapper, and because it receives the browser&amp;#x27;s native validation state (&amp;lt;code&amp;gt;:invalid&amp;lt;&amp;#x2F;code&amp;gt;, &amp;lt;code&amp;gt;:user-invalid&amp;lt;&amp;#x2F;code&amp;gt;), we can style our &amp;lt;em&amp;gt;entire custom component&amp;lt;&amp;#x2F;em&amp;gt; based on the hidden input&amp;#x27;s health. No more passing &amp;lt;code&amp;gt;isError&amp;lt;&amp;#x2F;code&amp;gt; props down three levels. No more &amp;lt;code&amp;gt;className={cx(styles.input, error &amp;amp;amp;&amp;amp;amp; styles.error)}&amp;lt;&amp;#x2F;code&amp;gt;.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;Just pure CSS:&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;css&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;* When the hidden input is invalid... *&amp;#x2F;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt;wrapper&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;has&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;input&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;user-invalid&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;) {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;  border-color&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; red&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;  animation&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; shake &amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt;0.2&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;s&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;* When the hidden input is required but empty... *&amp;#x2F;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt;wrapper&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;has&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;input&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;placeholder-shown&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;required&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;) .&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt;label&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;::&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt;after&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;  content&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;*&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;  color&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; red&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;We are letting the browser manage the state of the UI. The React component just renders the structure; the CSS reacts to the &amp;lt;em&amp;gt;truth&amp;lt;&amp;#x2F;em&amp;gt; of the DOM. (Note: &amp;lt;code&amp;gt;:has()&amp;lt;&amp;#x2F;code&amp;gt; is now supported in all major browsers as of late 2023).&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;conclusion&amp;quot;&amp;gt;Conclusion&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;I stopped trying to build &amp;quot;Form Components.&amp;quot; I started building &amp;quot;Input Wrappers.&amp;quot; It sounds like a semantic difference, but it changed everything. By respecting the native &amp;lt;code&amp;gt;&amp;amp;lt;input&amp;amp;gt;&amp;lt;&amp;#x2F;code&amp;gt; as the source of truth, I got so much for free.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;I got &amp;lt;code&amp;gt;FormData&amp;lt;&amp;#x2F;code&amp;gt; support.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;I got native validation.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;I got Server Action compatibility.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;I got CSS selectors like &amp;lt;code&amp;gt;:has(:user-invalid)&amp;lt;&amp;#x2F;code&amp;gt; to style my custom UI when the hidden input is unhappy.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;&amp;#x2F;ul&amp;gt;
&amp;lt;p&amp;gt;It’s a bit of a magic trick. It’s a bit of a lie. But if it submits like an input, validates like an input, and focuses like an input...&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;It’s an input. Don&amp;#x27;t build zombies. Build inputs.&amp;lt;&amp;#x2F;p&amp;gt;
</content>
            </entry>
            
        
            
            <entry>
                <title>The Invisible Work of a Focus Trap</title>
                <link href="https:&#x2F;&#x2F;werkbank.dev&#x2F;blog&#x2F;invisible-work-focus-trap&#x2F;"/>
                <updated>2026-01-15T00:00:00+0000</updated>
                <id>https:&#x2F;&#x2F;werkbank.dev&#x2F;blog&#x2F;invisible-work-focus-trap&#x2F;</id>
                <content type="html">&amp;lt;p class=&amp;quot;typl8-drop-cap&amp;quot;&amp;gt;You don&amp;#x27;t notice it when it works. You only notice it when it breaks. You open a modal. You hit Tab. The focus moves to the &amp;quot;Cancel&amp;quot; button. You hit Tab again. It moves to &amp;quot;Confirm&amp;quot;. You hit Tab again. And suddenly you are in the URL bar. Or worse, you are highlighting some random link in the footer behind the gray overlay. The illusion is broken. You aren&amp;#x27;t in a &amp;quot;dialog&amp;quot; anymore. You are just looking at a &amp;lt;code&amp;gt;div&amp;lt;&amp;#x2F;code&amp;gt; with a high z-index.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;the-problem&amp;quot;&amp;gt;The Problem&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;Building a Focus Trap sounds easy. &amp;quot;Just listen for the Tab key,&amp;quot; you say. &amp;quot;If they are on the last element, move them to the first.&amp;quot; I tried that. It works for about 5 minutes. Then you realize:&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;ol&amp;gt;
&amp;lt;li&amp;gt;What if the user Shift+Tabs (goes backwards)?&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;What if the user clicks outside the modal?&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;What if the DOM changes and the &amp;quot;last element&amp;quot; isn&amp;#x27;t the last element anymore?&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;What if the first element is disabled?&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;What if there is an iframe?&amp;lt;&amp;#x2F;strong&amp;gt; (The black hole of focus).&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;&amp;#x2F;ol&amp;gt;
&amp;lt;p&amp;gt;It turns into a nightmare of edge cases.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;the-rxjs-solution&amp;quot;&amp;gt;The RxJS Solution&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;In Werkbank, I use &amp;lt;code&amp;gt;useFocusTrap&amp;lt;&amp;#x2F;code&amp;gt;. And yes, I use RxJS.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;&amp;quot;Why not just use &amp;lt;code&amp;gt;react-focus-lock&amp;lt;&amp;#x2F;code&amp;gt;?&amp;quot; It&amp;#x27;s a great library. But I want to reduce the number of dependencies and I wanted full control over the behavior. I wanted to integrate it with our other hooks like &amp;lt;code&amp;gt;useOnEscape&amp;lt;&amp;#x2F;code&amp;gt; and &amp;lt;code&amp;gt;useOutsideClick&amp;lt;&amp;#x2F;code&amp;gt;.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;&amp;quot;Why not just use the &amp;lt;code&amp;gt;inert&amp;lt;&amp;#x2F;code&amp;gt; attribute?&amp;quot; &amp;lt;code&amp;gt;inert&amp;lt;&amp;#x2F;code&amp;gt; is amazing. It lets you disable the entire document &amp;lt;em&amp;gt;except&amp;lt;&amp;#x2F;em&amp;gt; your modal. But to use it, you have to find all the &amp;lt;em&amp;gt;siblings&amp;lt;&amp;#x2F;em&amp;gt; of your modal (and your modal&amp;#x27;s parents&amp;#x27; siblings) and mark them as inert. You have to walk the DOM tree up and down. It&amp;#x27;s expensive.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;Trapping focus is often cheaper than excluding everything else.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;&amp;quot;Why not use the native &amp;lt;code&amp;gt;&amp;amp;lt;dialog&amp;amp;gt;&amp;lt;&amp;#x2F;code&amp;gt; element?&amp;quot; You should! &amp;lt;code&amp;gt;&amp;amp;lt;dialog&amp;amp;gt;&amp;lt;&amp;#x2F;code&amp;gt; is fantastic. It handles focus trapping natively when you call &amp;lt;code&amp;gt;.showModal()&amp;lt;&amp;#x2F;code&amp;gt;. But sometimes you need a custom implementation. Maybe you need a specific animation that &amp;lt;code&amp;gt;&amp;amp;lt;dialog&amp;amp;gt;&amp;lt;&amp;#x2F;code&amp;gt; makes hard. Maybe you are building a complex panel system that isn&amp;#x27;t quite a dialog.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;When you &amp;lt;em&amp;gt;do&amp;lt;&amp;#x2F;em&amp;gt; need to roll your own, you need &amp;lt;code&amp;gt;useFocusTrap&amp;lt;&amp;#x2F;code&amp;gt;.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;It&amp;#x27;s not just for modals. In a complex, multi-panel layout (like the one you can build with &amp;lt;code&amp;gt;werkbank&amp;#x2F;component&amp;#x2F;grid&amp;lt;&amp;#x2F;code&amp;gt;), you might want to &amp;quot;trap&amp;quot; focus inside the active panel. If I&amp;#x27;m editing code in the left pane, pressing Tab shouldn&amp;#x27;t jump me to the terminal in the bottom pane. It should indent my code. Focus management is about context, not just blocking the user.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;Why RxJS? Because focus is a stream. It&amp;#x27;s not just about trapping the &amp;lt;em&amp;gt;key&amp;lt;&amp;#x2F;em&amp;gt;. It&amp;#x27;s about trapping the &amp;lt;em&amp;gt;event&amp;lt;&amp;#x2F;em&amp;gt;.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;useEffect&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;    let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; subscription&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; focusin$&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;        .&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;pipe&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;            filter&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;target&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt; !&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;currentDialog&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;contains&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(target))&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;        )&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;        .&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;subscribe&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;target&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;            &amp;#x2F;&amp;#x2F; Shadow DOM support? Use composedPath() here.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;            &amp;#x2F;&amp;#x2F; You tried to leave? Nice try.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;            focusFirstDescendant&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(currentDialog)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;        }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    &amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;    return&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; ()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; subscription&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;unsubscribe&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;},&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; [currentDialog])&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;We listen to &amp;lt;code&amp;gt;focusin&amp;lt;&amp;#x2F;code&amp;gt; globally. If the focus lands &amp;lt;em&amp;gt;anywhere&amp;lt;&amp;#x2F;em&amp;gt; outside our trap, we yank it back. Immediately. And because it&amp;#x27;s RxJS, cleanup is trivial. When the component unmounts, we unsubscribe. No dangling listeners. No memory leaks. This handles the &amp;quot;click outside&amp;quot; case. It handles the &amp;quot;programmatic focus&amp;quot; case. It handles the &amp;quot;screen reader navigation&amp;quot; case.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;A Note on Accessibility:&amp;lt;&amp;#x2F;strong&amp;gt;
Yanking focus is aggressive. It can be confusing. That&amp;#x27;s why your modal &amp;lt;em&amp;gt;must&amp;lt;&amp;#x2F;em&amp;gt; have &amp;lt;code&amp;gt;role=&amp;quot;dialog&amp;quot;&amp;lt;&amp;#x2F;code&amp;gt; and &amp;lt;code&amp;gt;aria-modal=&amp;quot;true&amp;quot;&amp;lt;&amp;#x2F;code&amp;gt;. This tells the screen reader, &amp;quot;Hey, I&amp;#x27;m a modal, I&amp;#x27;m trapping you on purpose.&amp;quot; Our JS is just the enforcement mechanism for browsers that don&amp;#x27;t fully respect that contract yet.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;the-algorithm&amp;quot;&amp;gt;The Algorithm&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;But where do we yank it back &amp;lt;em&amp;gt;to&amp;lt;&amp;#x2F;em&amp;gt;? We need to find the &amp;quot;First Descendant&amp;quot;. But not just the first child. The first &amp;lt;em&amp;gt;focusable&amp;lt;&amp;#x2F;em&amp;gt; child. And &amp;quot;focusable&amp;quot; is a messy concept in HTML.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;Is it an &amp;lt;code&amp;gt;&amp;amp;lt;a&amp;amp;gt;&amp;lt;&amp;#x2F;code&amp;gt; tag? Only if it has an &amp;lt;code&amp;gt;href&amp;lt;&amp;#x2F;code&amp;gt;.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;Is it a &amp;lt;code&amp;gt;&amp;amp;lt;button&amp;amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;? Only if it&amp;#x27;s not &amp;lt;code&amp;gt;disabled&amp;lt;&amp;#x2F;code&amp;gt;.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;Is it hidden? &amp;lt;code&amp;gt;aria-hidden&amp;lt;&amp;#x2F;code&amp;gt;? &amp;lt;code&amp;gt;display: none&amp;lt;&amp;#x2F;code&amp;gt;?&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;Does it have &amp;lt;code&amp;gt;tabindex=&amp;quot;-1&amp;quot;&amp;lt;&amp;#x2F;code&amp;gt;?&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;&amp;#x2F;ul&amp;gt;
&amp;lt;p&amp;gt;We have to traverse the tree. We have to check attributes.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;function&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; getFocusable&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;element&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; HTMLElement&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;) {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;	let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; focusable&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; element&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;querySelectorAll&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;		&amp;amp;#39;a[href], button, input, textarea, ...&amp;amp;#39;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;	)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;    &amp;#x2F;&amp;#x2F; ... filter out disabled and hidden ...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;&amp;quot;Wait, isn&amp;#x27;t &amp;lt;code&amp;gt;querySelectorAll&amp;lt;&amp;#x2F;code&amp;gt; slow?&amp;quot; Yes, if you run it on every keypress. But we don&amp;#x27;t. We run it lazily, and we can use &amp;lt;code&amp;gt;MutationObserver&amp;lt;&amp;#x2F;code&amp;gt; (another hook!) to invalidate the cache if the DOM changes.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;why-it-matters&amp;quot;&amp;gt;Why It Matters&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;This is the kind of code that nobody wants to write. It&amp;#x27;s unglamorous. It&amp;#x27;s &amp;quot;plumbing&amp;quot;. It has zero visual impact. But it&amp;#x27;s the difference between a &amp;quot;React Component&amp;quot; and a &amp;quot;User Interface Element&amp;quot;. A native OS dialog traps focus. A native OS menu manages arrow keys.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;If we want the web to feel like an app, we have to respect these rules. We can&amp;#x27;t just slap a &amp;lt;code&amp;gt;position: fixed&amp;lt;&amp;#x2F;code&amp;gt; on a div and call it a day. We are talking about &amp;lt;strong&amp;gt;Modal&amp;lt;&amp;#x2F;strong&amp;gt; dialogs here. Modeless dialogs (like a find bar) shouldn&amp;#x27;t trap focus. But if you block the UI with an overlay, you must block the focus too.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;We have to do the invisible work.&amp;lt;&amp;#x2F;p&amp;gt;
</content>
            </entry>
            
        
            
            <entry>
                <title>Type-Safe Routing Without the Build Step</title>
                <link href="https:&#x2F;&#x2F;werkbank.dev&#x2F;blog&#x2F;schema-first-router&#x2F;"/>
                <updated>2026-01-14T00:00:00+0000</updated>
                <id>https:&#x2F;&#x2F;werkbank.dev&#x2F;blog&#x2F;schema-first-router&#x2F;</id>
                <content type="html">&amp;lt;p class=&amp;quot;typl8-drop-cap&amp;quot;&amp;gt;It always starts with a string. &amp;lt;code&amp;gt;const { id } = useParams()&amp;lt;&amp;#x2F;code&amp;gt;. And right there, I&amp;#x27;m already annoyed. What is &amp;lt;code&amp;gt;id&amp;lt;&amp;#x2F;code&amp;gt;? It&amp;#x27;s a string. But my database says it&amp;#x27;s a number. So now I have to parse it. &amp;lt;code&amp;gt;parseInt(id, 10)&amp;lt;&amp;#x2F;code&amp;gt;. But wait, what if it&amp;#x27;s undefined? What if the user typed &amp;quot;banana&amp;quot; into the URL bar? Now I&amp;#x27;m writing &amp;lt;code&amp;gt;isNaN&amp;lt;&amp;#x2F;code&amp;gt; checks inside my component. I&amp;#x27;m doing validation logic inside my view layer. Again. Why are we still doing this in 2026?&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;I look around at the ecosystem and everything is... loud. Everyone is shouting about Server Side Rendering. Hydration. Edge functions. File-based routing where the file system is the API. And I get it, I do, SEO is important, performance is key. But sometimes I just want to build an app. A real, rich, thick-client Single Page App. I don&amp;#x27;t want a server process watching my files. I don&amp;#x27;t want a build step that generates a 5,000 line &amp;lt;code&amp;gt;routes.d.ts&amp;lt;&amp;#x2F;code&amp;gt; file that I have to gitignore (or worse, commit). I just want TypeScript to know what my URL is.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;I remember looking at &amp;lt;a rel=&amp;quot;external&amp;quot; href=&amp;quot;https:&amp;#x2F;&amp;#x2F;www.servant.dev&amp;#x2F;&amp;quot;&amp;gt;Servant&amp;lt;&amp;#x2F;a&amp;gt;. It&amp;#x27;s this Haskell web framework that treats APIs differently. In Servant, you don&amp;#x27;t write a route handler and then hope it matches the URL. You define the API as a &amp;lt;em&amp;gt;Type&amp;lt;&amp;#x2F;em&amp;gt;. The type &amp;lt;em&amp;gt;is&amp;lt;&amp;#x2F;em&amp;gt; the spec. The implementation is just a function that has to satisfy that type. If you change the type, the compiler screams at you until you fix the implementation. In Servant, that same route looks like this:&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;haskell&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;type UserAPI&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;users&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; :&amp;amp;gt; Capture&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;userId&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; Int :&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;posts&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; :&amp;amp;gt; Capture&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;postId&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; String :&amp;amp;gt; Get&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; &amp;amp;#39;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;[&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;JSON&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; Post&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;It was beautiful. It was strict. It was... correct. It inspired me to ask: Why can&amp;#x27;t I have that in React?&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;So I started hacking. I didn&amp;#x27;t want &amp;quot;paths&amp;quot; like &amp;lt;code&amp;gt;&amp;#x2F;users&amp;#x2F;:id&amp;lt;&amp;#x2F;code&amp;gt;. That&amp;#x27;s just a string with a colon in it. It&amp;#x27;s weak. I wanted a schema. I wanted to say: &amp;quot;This route consists of the static segment &amp;#x27;users&amp;#x27;, followed by a Number, followed by &amp;#x27;posts&amp;#x27;, followed by a String.&amp;quot; I wanted this:&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;path&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; [&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;users&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; number&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;posts&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; string&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;()]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;That&amp;#x27;s not a string. That&amp;#x27;s a tuple. That&amp;#x27;s data. And because it&amp;#x27;s data, I can infer things from it.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;the-magic-type-inference-without-codegen&amp;quot;&amp;gt;The &amp;quot;Magic&amp;quot;: Type Inference Without Codegen&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;But how do you get TypeScript to understand that &amp;lt;code&amp;gt;number()&amp;lt;&amp;#x2F;code&amp;gt; in the array means the prop passed to your component should be a &amp;lt;code&amp;gt;number&amp;lt;&amp;#x2F;code&amp;gt;? This is where I went down the rabbit hole. Recursive types. I spent nights staring at &amp;lt;code&amp;gt;infer&amp;lt;&amp;#x2F;code&amp;gt; keywords until my eyes blurred. I wanted to avoid code generation at all costs. I wanted the IDE to just &amp;lt;em&amp;gt;know&amp;lt;&amp;#x2F;em&amp;gt;. I ended up with something like this. It looks scary, but it&amp;#x27;s actually kind of elegant if you squint:&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;type&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; Params&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt;Arr&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; Acc&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; extends&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; Array&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;any&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; []&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; Arr&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; extends readonly&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; [&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;	infer&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; Head&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;	...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;infer&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; Tail&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt;]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;	?&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; Head&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; extends&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; BaseSchema&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;any&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; any&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; any&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;	?&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; Params&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt;Tail&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; [&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt;Acc&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; InferOutput&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt;Head&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt;]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;	:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; Params&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt;Tail&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; Acc&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;	:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; Acc&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;It walks the array. Is this item a Schema? Yes? Extract its type. No? Ignore it. And suddenly, it worked. I could hover over &amp;lt;code&amp;gt;props.params&amp;lt;&amp;#x2F;code&amp;gt; in my component and see &amp;lt;code&amp;gt;[number, string]&amp;lt;&amp;#x2F;code&amp;gt;. No &amp;lt;code&amp;gt;any&amp;lt;&amp;#x2F;code&amp;gt;. No &amp;lt;code&amp;gt;string | undefined&amp;lt;&amp;#x2F;code&amp;gt;. Just the raw, validated types. It felt like magic, but it wasn&amp;#x27;t. It was just inference.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;The best part? It&amp;#x27;s basically OpenAPI for your internal routes. You define the contract first. &amp;quot;This page &amp;lt;em&amp;gt;requires&amp;lt;&amp;#x2F;em&amp;gt; a number.&amp;quot; The router enforces it. If the URL doesn&amp;#x27;t match the schema (like if someone types &amp;lt;code&amp;gt;&amp;#x2F;users&amp;#x2F;banana&amp;lt;&amp;#x2F;code&amp;gt;), the router doesn&amp;#x27;t even try to render the component. It blocks it at the door. My components became pure. They didn&amp;#x27;t have to worry about parsing or validation anymore. They just received data.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;I know, I know. &amp;quot;Another router?&amp;quot; But this one feels different. It feels like what we should have had all along if we hadn&amp;#x27;t gotten so distracted by making the server do everything. It treats the URL as a source of truth, not just a string of characters.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;I built this because I was tired of guessing. I was tired of &amp;lt;code&amp;gt;as string&amp;lt;&amp;#x2F;code&amp;gt;. I was tired of runtime errors that should have been compile-time errors. I built it because I wanted to trust my code again.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h2 id=&amp;quot;how-it-works&amp;quot;&amp;gt;How it works&amp;lt;&amp;#x2F;h2&amp;gt;
&amp;lt;p&amp;gt;So, how do you actually use this thing? It&amp;#x27;s a two-step process: define the schema, then implement the router. First, you define your routes. This is your contract.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;import&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E78284;&amp;quot;&amp;gt; *&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; as&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; v&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; from&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;valibot&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; 1. Define your custom types&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; The router works with ANY Valibot schema.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; Want a number from the URL? Transform the string.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; Num&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; v&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;pipe&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;	v&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;string&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;	v&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;transform&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;input&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; Number&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;parseInt&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(input&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; 10&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;))&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; Want a UUID? Validate it.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; Uuid&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; v&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;pipe&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(v&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;string&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; v&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;uuid&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;())&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; 2. Define your routes&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; todoConfig&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;	app&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;		path&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; [&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;&amp;#x2F;&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;		children&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;			home&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; [&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;home&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;			&amp;#x2F;&amp;#x2F; A route with search params for filtering&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;			todos&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;				path&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; [&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;todos&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;				searchParams&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; v&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;object&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;					filter&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; v&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;optional&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(v&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;enum&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;([&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;active&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;completed&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;]))&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;				}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;			},&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;			&amp;#x2F;&amp;#x2F; A route with a UUID path parameter&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;			todo&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; [&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;todo&amp;#x2F;&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; Uuid]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;			&amp;#x2F;&amp;#x2F; A route with a Number path parameter (e.g. &amp;#x2F;archive&amp;#x2F;2023)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;			archive&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; [&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;archive&amp;#x2F;&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; Num]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;		},&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;	},&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; as const&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;Then, you create the router. This is where the magic happens. The &amp;lt;code&amp;gt;createRouter&amp;lt;&amp;#x2F;code&amp;gt; function takes your config and forces you to provide components that match the schema.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;tsx&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;import&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; createRouter&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; from&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;werkbank&amp;#x2F;router&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; routerConfig&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; createRouter&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(todoConfig&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;, {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;	app&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;		&amp;#x2F;&amp;#x2F; The parent component receives &amp;amp;#39;children&amp;amp;#39; - this is your Outlet!&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;		component&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; ({&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt; children&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; })&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; &amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;main&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;children&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;lt;&amp;#x2F;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;main&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;		children&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;			home&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;				component&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; ()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; &amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;div&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;Home&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;lt;&amp;#x2F;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;div&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;			},&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;			todos&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;				&amp;#x2F;&amp;#x2F; Supports Code Splitting!&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;				&amp;#x2F;&amp;#x2F; Just pass a dynamic import as &amp;amp;#39;preload&amp;amp;#39; and a Lazy component&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;				component&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; React&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;lazy&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; import&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;.&amp;#x2F;TodosList&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;))&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;				preload&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; ()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; import&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;.&amp;#x2F;TodosList&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;			},&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;			todo&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;				&amp;#x2F;&amp;#x2F; params is inferred as [string] automatically!&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;				component&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; ({&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt; params&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; })&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;					return&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; &amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;h1&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;Todo: &amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;params[&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt;0&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;lt;&amp;#x2F;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;h1&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;				},&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;			},&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;			archive&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;				&amp;#x2F;&amp;#x2F; params is inferred as [number] automatically!&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;				component&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; ({&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt; params&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; })&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;					return&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; &amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;h1&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;Archive Year: &amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;params[&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt;0&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;lt;&amp;#x2F;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;h1&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;				},&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;			},&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;		},&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;	},&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;A Note on Tuples vs. Named Parameters&amp;lt;&amp;#x2F;strong&amp;gt;: You might notice &amp;lt;code&amp;gt;params[0]&amp;lt;&amp;#x2F;code&amp;gt;. &amp;quot;Wait, I have to access params by index? That&amp;#x27;s fragile!&amp;quot; Actually, it&amp;#x27;s the opposite. It&amp;#x27;s robust. By using tuples, we get instant, zero-config type inference without a build step. If I were to swap the order in the schema—putting the string before the number—TypeScript would immediately flag every usage of &amp;lt;code&amp;gt;params[0]&amp;lt;&amp;#x2F;code&amp;gt; in my component. It would say: &amp;quot;Type &amp;#x27;string&amp;#x27; is not assignable to type &amp;#x27;number&amp;#x27;&amp;quot;. It&amp;#x27;s strict, but it&amp;#x27;s safe. It forces you to respect the order of data as defined in your source of truth.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;And finally, you render it:&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;tsx&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;import&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; Router&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; from&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;werkbank&amp;#x2F;router&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;function&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; App&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;() {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;    return&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; &amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #F4B8E4;&amp;quot;&amp;gt;Router&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt; config&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;routerConfig&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; &amp;#x2F;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;Links are also type-safe. You can&amp;#x27;t link to a route that doesn&amp;#x27;t exist, and you can&amp;#x27;t forget a parameter.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;tsx&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;import&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; createLinks&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; from&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;werkbank&amp;#x2F;router&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;let&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; links&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; createLinks&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(todoConfig)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; This works&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #F4B8E4;&amp;quot;&amp;gt;Link&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt; href&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;links&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;app&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;todos&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; searchParams&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; filter&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;active&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; } }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;Active Todos&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;lt;&amp;#x2F;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #F4B8E4;&amp;quot;&amp;gt;Link&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; This works (Type-safe UUID!)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #F4B8E4;&amp;quot;&amp;gt;Link&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt; href&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;links&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;app&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;todo&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; params&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; [&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;550e8400-e29b-41d4-a716-446655440000&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;]&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;View Todo&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;lt;&amp;#x2F;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #F4B8E4;&amp;quot;&amp;gt;Link&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; This errors at compile time! (Missing params)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #F4B8E4;&amp;quot;&amp;gt;Link&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt; href&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;links&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;app&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;todo&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;View Todo&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;lt;&amp;#x2F;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #F4B8E4;&amp;quot;&amp;gt;Link&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;&amp;lt;h3 id=&amp;quot;is-the-verbosity-worth-it&amp;quot;&amp;gt;Is the verbosity worth it?&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;I hear you. &amp;lt;code&amp;gt;&amp;amp;lt;Link href={links.app().todo(...)}&amp;amp;gt;&amp;lt;&amp;#x2F;code&amp;gt; is longer than &amp;lt;code&amp;gt;&amp;amp;lt;Link to=&amp;quot;&amp;#x2F;todo&amp;#x2F;123&amp;quot;&amp;amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;. But ask yourself: how many times have you broken a link because you renamed a route? Or forgot a required query parameter? With this approach, a route rename is a simple &amp;quot;Rename Symbol&amp;quot; in your IDE. Every link updates automatically. The verbosity buys you confidence.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h2 id=&amp;quot;getting-started&amp;quot;&amp;gt;Getting Started&amp;lt;&amp;#x2F;h2&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a rel=&amp;quot;external&amp;quot; href=&amp;quot;https:&amp;#x2F;&amp;#x2F;docs.werkbank.dev&amp;#x2F;documents&amp;#x2F;Getting_Started.html&amp;quot;&amp;gt;Getting Started&amp;lt;&amp;#x2F;a&amp;gt;&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a rel=&amp;quot;external&amp;quot; href=&amp;quot;https:&amp;#x2F;&amp;#x2F;docs.werkbank.dev&amp;#x2F;documents&amp;#x2F;Getting_Started.Router.html&amp;quot;&amp;gt;Router Guide&amp;lt;&amp;#x2F;a&amp;gt;&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;&amp;#x2F;ul&amp;gt;
&amp;lt;h2 id=&amp;quot;disclaimer&amp;quot;&amp;gt;Disclaimer&amp;lt;&amp;#x2F;h2&amp;gt;
&amp;lt;p&amp;gt;This is a Proof of Concept (PoC). It&amp;#x27;s running in my personal workspace. It&amp;#x27;s not on GitHub yet. It&amp;#x27;s not battle-tested in a million-user app. It&amp;#x27;s an experiment in &amp;quot;What if?&amp;quot;. I plan to open source this properly at a later date, once I&amp;#x27;ve ironed out the kinks and written some actual documentation. But for now, I just wanted to share the idea. Because sometimes, the best way to move forward is to look at what we&amp;#x27;re doing and ask: &amp;quot;Does it have to be this hard?&amp;quot;&amp;lt;&amp;#x2F;p&amp;gt;
</content>
            </entry>
            
        
            
            <entry>
                <title>Type-Safe React Forms</title>
                <link href="https:&#x2F;&#x2F;werkbank.dev&#x2F;blog&#x2F;type-safe-react-forms&#x2F;"/>
                <updated>2026-01-14T00:00:00+0000</updated>
                <id>https:&#x2F;&#x2F;werkbank.dev&#x2F;blog&#x2F;type-safe-react-forms&#x2F;</id>
                <content type="html">&amp;lt;p class=&amp;quot;typl8-drop-cap&amp;quot;&amp;gt;It starts with a schema. It always starts with a schema.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; Define the rule once&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;const&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; password&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; string&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;([&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;minLength&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt;8&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)])&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;I define my validation rule: &amp;quot;Password must be at least 8 characters.&amp;quot; Simple enough. Then I switch context to my component.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;tsx&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;input&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt; type&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;password&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; &amp;#x2F;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;And I pause. I look at the schema. I look at the input. And I sigh.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;tsx&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;input&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt; type&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;password&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt; minLength&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt;8&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; &amp;#x2F;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;I have to type it again. I have to manually tell the browser what I just told my validator. And right there, the drift begins. Two weeks later, security comes in. &amp;quot;Passwords need to be 10 characters now.&amp;quot; I update the schema. &amp;lt;code&amp;gt;minLength(10)&amp;lt;&amp;#x2F;code&amp;gt;. I push the code. And then I get a bug report. &amp;quot;The error message says 10 characters, but the browser let me submit 8.&amp;quot;&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;I forgot the input. Of course I forgot the input. Why wouldn&amp;#x27;t I? It&amp;#x27;s a completely separate file, a completely separate line of code, disconnected from the source of truth. Why are we still doing this?&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;I look at &amp;lt;code&amp;gt;react-hook-form&amp;lt;&amp;#x2F;code&amp;gt;. It&amp;#x27;s great. It&amp;#x27;s powerful. But it feels... manual. &amp;lt;code&amp;gt;register(&amp;quot;password&amp;quot;, { minLength: 8 })&amp;lt;&amp;#x2F;code&amp;gt;. I&amp;#x27;m still defining the rules in the UI layer. I&amp;#x27;m still shifting gears manually. I wanted something else. I wanted an &amp;lt;strong&amp;gt;Orchestrator&amp;lt;&amp;#x2F;strong&amp;gt;.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;the-idea&amp;quot;&amp;gt;The Idea&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;What if the schema wasn&amp;#x27;t just a gatekeeper? What if it was the blueprint? I didn&amp;#x27;t want to write validation logic &amp;lt;em&amp;gt;and&amp;lt;&amp;#x2F;em&amp;gt; UI logic. I wanted to write the &amp;lt;em&amp;gt;definition&amp;lt;&amp;#x2F;em&amp;gt; of the data, and have the UI just... happen.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;If I say &amp;lt;code&amp;gt;string([email()])&amp;lt;&amp;#x2F;code&amp;gt;, the input should know it&amp;#x27;s &amp;lt;code&amp;gt;type=&amp;quot;email&amp;quot;&amp;lt;&amp;#x2F;code&amp;gt;.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;If I say &amp;lt;code&amp;gt;number()&amp;lt;&amp;#x2F;code&amp;gt;, the input should be &amp;lt;code&amp;gt;type=&amp;quot;number&amp;quot;&amp;lt;&amp;#x2F;code&amp;gt;.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;If I say &amp;lt;code&amp;gt;minLength(8)&amp;lt;&amp;#x2F;code&amp;gt;, the input should have &amp;lt;code&amp;gt;minLength={8}&amp;lt;&amp;#x2F;code&amp;gt;.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;&amp;#x2F;ul&amp;gt;
&amp;lt;p&amp;gt;I wanted to define the rules once, in Valibot, and have them ripple through the entire application.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;the-solution-the-schema-as-the-orchestrator&amp;quot;&amp;gt;The Solution: The Schema as the Orchestrator&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;So I built it. A form library where the schema drives the UI. It looks like this:&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;tsx&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;import&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E78284;&amp;quot;&amp;gt; *&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; as&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; v&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; from&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;valibot&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;import&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;  Form&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;  useFormFields&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;  type&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; SubmitHandler&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; from&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;werkbank&amp;#x2F;component&amp;#x2F;form&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; 1. Define the Single Source of Truth&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;const&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; LoginSchema&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; v&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;object&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;  email&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; v&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;pipe&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(v&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;string&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; v&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;email&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;())&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;  password&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; v&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;pipe&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(v&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;string&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; v&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;minLength&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt;8&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;))&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;function&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; LoginForm&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;() {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;  &amp;#x2F;&amp;#x2F; 2. Let the Orchestrator do the work&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;  &amp;#x2F;&amp;#x2F; The schema acts as the conductor, determining props for every field.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;  const&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; formFields&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; useFormFields&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(LoginSchema)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;  &amp;#x2F;&amp;#x2F; 3. Typed Submit Handler&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;  &amp;#x2F;&amp;#x2F; &amp;amp;#39;payload&amp;amp;#39; is inferred as { email: string; password: string }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;  const&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; handleSubmit&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;font-style: italic;&amp;quot;&amp;gt; SubmitHandler&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;typeof&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;font-style: italic;&amp;quot;&amp;gt; LoginSchema&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #99D1DB;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; (&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;payload&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;    console&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;log&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;Login with:&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; payload&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;email)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;  };&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;  return&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; (&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;    &amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #F4B8E4;&amp;quot;&amp;gt;Form&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt; schema&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;LoginSchema&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt; onSubmit&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;handleSubmit&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;      &amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;label&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt; htmlFor&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;formFields&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;email&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;id&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;Email&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;lt;&amp;#x2F;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;label&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;      {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;* 4. Spread the props. That&amp;amp;#39;s it. *&amp;#x2F;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;      {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;* This input now has type=&amp;amp;quot;email&amp;amp;quot;, required, and id *&amp;#x2F;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;      &amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;input&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;formFields&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;email&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; &amp;#x2F;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;      &amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;label&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt; htmlFor&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;formFields&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;password&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;id&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;Password&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;lt;&amp;#x2F;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;label&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;      {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;* This input now has minLength={8}, required, and id *&amp;#x2F;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;      &amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;input&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;formFields&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;password&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt; type&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;password&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; &amp;#x2F;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;      &amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;button&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt; type&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;submit&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;Login&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;lt;&amp;#x2F;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;button&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;    &amp;amp;lt;&amp;#x2F;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #F4B8E4;&amp;quot;&amp;gt;Form&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;  )&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;Do you see what happened there?&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;formFields.email&amp;lt;&amp;#x2F;code&amp;gt; isn&amp;#x27;t just &amp;lt;code&amp;gt;name=&amp;quot;email&amp;quot;&amp;lt;&amp;#x2F;code&amp;gt;. It&amp;#x27;s &amp;lt;code&amp;gt;type=&amp;quot;email&amp;quot;&amp;lt;&amp;#x2F;code&amp;gt;. It&amp;#x27;s &amp;lt;code&amp;gt;required&amp;lt;&amp;#x2F;code&amp;gt;.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;formFields.password&amp;lt;&amp;#x2F;code&amp;gt; has &amp;lt;code&amp;gt;minLength={8}&amp;lt;&amp;#x2F;code&amp;gt;.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;&amp;#x2F;ul&amp;gt;
&amp;lt;p&amp;gt;If I change the schema to &amp;lt;code&amp;gt;minLength(10)&amp;lt;&amp;#x2F;code&amp;gt;, the input updates. Automatically. No drift. No &amp;quot;double maintenance.&amp;quot;&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;why-not-just-use-the-dom&amp;quot;&amp;gt;Why Not Just Use the DOM?&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;I hear the web purists. &amp;quot;Just use &amp;lt;code&amp;gt;FormData&amp;lt;&amp;#x2F;code&amp;gt;! The DOM is the ultimate source of truth!&amp;quot; And they have a point. The DOM &amp;lt;em&amp;gt;is&amp;lt;&amp;#x2F;em&amp;gt; excellent at holding state. But the DOM is terrible at &amp;lt;em&amp;gt;types&amp;lt;&amp;#x2F;em&amp;gt;. To the DOM, everything is a string.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;&amp;quot;123&amp;quot; is a string.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;&amp;quot;true&amp;quot; is a string.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;&amp;quot;2023-01-01&amp;quot; is a string.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;&amp;#x2F;ul&amp;gt;
&amp;lt;p&amp;gt;If I rely solely on the DOM, I&amp;#x27;m back to parsing strings manually in my submit handler. &amp;lt;code&amp;gt;parseInt(data.get(&amp;#x27;age&amp;#x27;))&amp;lt;&amp;#x2F;code&amp;gt;. &amp;lt;code&amp;gt;data.get(&amp;#x27;isAdmin&amp;#x27;) === &amp;#x27;on&amp;#x27;&amp;lt;&amp;#x2F;code&amp;gt;. This is where &amp;quot;Schema-First&amp;quot; shines. The schema bridges the gap. It tells the DOM how to behave (attributes), but it also tells the code how to interpret the result (parsing).&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;When &amp;lt;code&amp;gt;werkbank&amp;lt;&amp;#x2F;code&amp;gt; hands you the data in &amp;lt;code&amp;gt;onSubmit&amp;lt;&amp;#x2F;code&amp;gt;, it&amp;#x27;s not a bag of strings. It&amp;#x27;s numbers. It&amp;#x27;s booleans. It&amp;#x27;s Dates. It&amp;#x27;s real, typed data. The schema handles the transformation layer so you don&amp;#x27;t have to.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;performance-the-uncontrolled-advantage&amp;quot;&amp;gt;Performance: The Uncontrolled Advantage&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;&amp;quot;But does this re-render my whole app on every keystroke?&amp;quot; No. This is an &amp;lt;strong&amp;gt;uncontrolled&amp;lt;&amp;#x2F;strong&amp;gt; form library. We are not binding &amp;lt;code&amp;gt;value&amp;lt;&amp;#x2F;code&amp;gt; and &amp;lt;code&amp;gt;onChange&amp;lt;&amp;#x2F;code&amp;gt; to React state for every character you type. The &amp;lt;code&amp;gt;useFormFields&amp;lt;&amp;#x2F;code&amp;gt; hook uses &amp;lt;code&amp;gt;useMemo&amp;lt;&amp;#x2F;code&amp;gt; to compute the attributes &amp;lt;em&amp;gt;once&amp;lt;&amp;#x2F;em&amp;gt; (memoized based on the schema). The returned object is stable. When you type in the input, React stays out of the way. The browser handles the update. We only touch React state when:&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;ol&amp;gt;
&amp;lt;li&amp;gt;You submit the form.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;A validation error occurs (and we need to show UI).&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;&amp;#x2F;ol&amp;gt;
&amp;lt;p&amp;gt;This means you can have a form with 500 inputs, and typing in the 500th one feels just as fast as typing in the first. Zero lag. Zero unnecessary re-renders.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;it-goes-deeper-enums-and-automatic-ui&amp;quot;&amp;gt;It Goes Deeper: Enums and Automatic UI&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;But why stop at simple attributes? What about the annoying stuff? Selects. Radio groups. Defining a dropdown in React is usually a chore. You have to map over options, manage keys, handle values. But if I have an Enum in my schema, I already &amp;lt;em&amp;gt;know&amp;lt;&amp;#x2F;em&amp;gt; what the options are.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;const&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; MonsterEnum&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;  Kraken&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;K&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;  Sasquatch&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;S&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;  Mothman&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;M&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;  &amp;#x2F;&amp;#x2F; ...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;};&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;const&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; schema&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; object&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;  monster&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; v&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;enum&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(MonsterEnum)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;The library sees this. It knows it&amp;#x27;s an Enum. So &amp;lt;code&amp;gt;useFormFields&amp;lt;&amp;#x2F;code&amp;gt; gives me everything I need to render a radio group or a select, without me typing the options again.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;tsx&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;const&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; fields&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; useFormFields&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(schema)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; It gives me the options array automatically!&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;select&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;fields&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;monster&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;select&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;  {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;fields&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;monster&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;options&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;map&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;opt&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; (&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;    &amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;option&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt; key&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;opt&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;name&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt; value&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;opt&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;value&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;opt&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;name&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;lt;&amp;#x2F;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;option&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;  ))&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;lt;&amp;#x2F;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;select&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;When you submit the form, &amp;lt;code&amp;gt;werkbank&amp;lt;&amp;#x2F;code&amp;gt; just reads the hidden input. It doesn&amp;#x27;t care about your fancy UI. It just cares about the data. This avoids the fragile dance of syncing React state back to the DOM manually. We let the DOM hold the state, even for custom components.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;what-about-dynamic-forms&amp;quot;&amp;gt;What about Dynamic Forms?&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;&amp;quot;This is cool for static forms,&amp;quot; you say. &amp;quot;But I have a list of users that I can add and remove. I need &amp;lt;code&amp;gt;useFieldArray&amp;lt;&amp;#x2F;code&amp;gt;.&amp;quot; Dynamic forms are where many libraries fall apart. They force you into complex state management just to add a row. Because we rely on the DOM structure, handling arrays is surprisingly simple. You just render the inputs. If your schema expects an array of strings, you just render inputs with the same &amp;lt;code&amp;gt;name&amp;lt;&amp;#x2F;code&amp;gt;.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;tsx&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; Schema: emails: array(string([email()]))&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; DOM:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;input&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt; name&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;emails&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt; type&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;email&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; &amp;#x2F;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;input&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt; name&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;emails&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt; type&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;email&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; &amp;#x2F;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;When you submit, &amp;lt;code&amp;gt;werkbank&amp;lt;&amp;#x2F;code&amp;gt; sees multiple inputs with the name &amp;quot;emails&amp;quot;, collects them into an array, and validates them against the array schema. Since the DOM order &amp;lt;em&amp;gt;is&amp;lt;&amp;#x2F;em&amp;gt; the array order, reordering items is just reordering the rendered components.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;You don&amp;#x27;t need a complex &amp;lt;code&amp;gt;append&amp;lt;&amp;#x2F;code&amp;gt; or &amp;lt;code&amp;gt;remove&amp;lt;&amp;#x2F;code&amp;gt; API. You just render React components. If you want to add a row? Just update your local state to render another &amp;lt;code&amp;gt;&amp;amp;lt;input&amp;amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;. The form library doesn&amp;#x27;t care &amp;lt;em&amp;gt;how&amp;lt;&amp;#x2F;em&amp;gt; the inputs got there, only that they exist when you hit submit.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;bring-your-own-components&amp;quot;&amp;gt;Bring Your Own Components&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;&amp;quot;But I have my own component library!&amp;quot; I hear you. You don&amp;#x27;t want to rewrite your &amp;lt;code&amp;gt;FancyInput&amp;lt;&amp;#x2F;code&amp;gt;. You just want it to validate. That&amp;#x27;s where &amp;lt;code&amp;gt;useInputValidation&amp;lt;&amp;#x2F;code&amp;gt; comes in. It&amp;#x27;s the low-level hook that powers everything else. It connects any component to the Form Context.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;tsx&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;import&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; useInputValidation&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; from&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;werkbank&amp;#x2F;hook&amp;#x2F;useInputValidation&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;function&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; MyFancyInput&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;({&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt; name&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; ...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EA999C;font-style: italic;&amp;quot;&amp;gt;props&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; }) {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;  &amp;#x2F;&amp;#x2F; Hooks into the parent &amp;amp;lt;Form&amp;amp;gt;, finds the schema for &amp;amp;#39;name&amp;amp;#39;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;  &amp;#x2F;&amp;#x2F; and gives you validation handlers.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;  const&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; onChange&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; onBlur&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt; validate&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; useInputValidation&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; name&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;  return&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; (&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;    &amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;div&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt; className&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;fancy-wrapper&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;      &amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;input&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt;        name&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;name&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt;        onChange&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;onChange&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt;        onBlur&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;onBlur&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;        {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;props&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;      &amp;#x2F;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;    &amp;amp;lt;&amp;#x2F;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;div&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;  )&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;Now &amp;lt;code&amp;gt;MyFancyInput&amp;lt;&amp;#x2F;code&amp;gt; participates in the form lifecycle. It validates on blur. It validates on submit. It reports errors. And you didn&amp;#x27;t have to write a single &amp;lt;code&amp;gt;setState&amp;lt;&amp;#x2F;code&amp;gt;. And because we spread &amp;lt;code&amp;gt;...props&amp;lt;&amp;#x2F;code&amp;gt; last, you can still override anything manually if you have a weird edge case.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;closer-to-the-platform-but-not-too-close&amp;quot;&amp;gt;Closer to the Platform (But Not Too Close)&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;The best part? This isn&amp;#x27;t re-inventing validation. It&amp;#x27;s using the platform. We extract these attributes so we can leverage the browser&amp;#x27;s built-in &amp;lt;a rel=&amp;quot;external&amp;quot; href=&amp;quot;https:&amp;#x2F;&amp;#x2F;developer.mozilla.org&amp;#x2F;en-US&amp;#x2F;docs&amp;#x2F;Web&amp;#x2F;HTML&amp;#x2F;Guides&amp;#x2F;Constraint_validation&amp;quot;&amp;gt;Constraint Validation API&amp;lt;&amp;#x2F;a&amp;gt;. When you click submit, we don&amp;#x27;t run a heavy JS validation suite immediately. We let the browser check the &amp;lt;code&amp;gt;type=&amp;quot;email&amp;quot;&amp;lt;&amp;#x2F;code&amp;gt;. We let the browser check the &amp;lt;code&amp;gt;minLength&amp;lt;&amp;#x2F;code&amp;gt;. We get the red outlines and the tooltips for free. We also get the correct mobile keyboards (email, numeric) for free, just by using the right standard attributes.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;&amp;quot;But wait,&amp;quot;&amp;lt;&amp;#x2F;strong&amp;gt; I hear you say. &amp;lt;strong&amp;gt;&amp;quot;Native validation UI is ugly and inconsistent.&amp;quot;&amp;lt;&amp;#x2F;strong&amp;gt; You&amp;#x27;re right. The default browser bubbles are terrible. That&amp;#x27;s why we use the API (&amp;lt;code&amp;gt;reportValidity&amp;lt;&amp;#x2F;code&amp;gt;, &amp;lt;code&amp;gt;setCustomValidity&amp;lt;&amp;#x2F;code&amp;gt;) for the logic, but you can still render your own UI. The library exposes &amp;lt;code&amp;gt;onSchemaIssues&amp;lt;&amp;#x2F;code&amp;gt; and &amp;lt;code&amp;gt;onValidationError&amp;lt;&amp;#x2F;code&amp;gt; so you can suppress the default bubbles and show your own beautiful, accessible error messages.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;We use the browser as the engine, not necessarily the paint.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;accessibility-is-not-optional&amp;quot;&amp;gt;Accessibility is Not Optional&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;One thing that often gets lost in &amp;quot;magic&amp;quot; form libraries is accessibility. When an error happens, does the screen reader know? Because &amp;lt;code&amp;gt;useFormFields&amp;lt;&amp;#x2F;code&amp;gt; generates unique IDs for every field, we can automatically link inputs to their error messages.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;tsx&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;font-style: italic;&amp;quot;&amp;gt;&amp;#x2F;&amp;#x2F; The hook provides the IDs you need for ARIA&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;input&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;  {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;...&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;formFields&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;email&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt;  aria-describedby&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;`&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;${&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;formFields&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;email&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;id&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;-error`&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt;  aria-invalid&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;!!&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;errors&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;email&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;#x2F;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;span&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #E5C890;&amp;quot;&amp;gt; id&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;=&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;`&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;${&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;formFields&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;email&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;id&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;-error`&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;errors&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;.&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;email&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;lt;&amp;#x2F;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;&amp;quot;&amp;gt;span&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;We also handle focus management. When validation fails on submit, we automatically focus the first invalid field, ensuring keyboard users aren&amp;#x27;t left stranded. It feels native. It feels fast. It feels like we&amp;#x27;re working &amp;lt;em&amp;gt;with&amp;lt;&amp;#x2F;em&amp;gt; the browser, not fighting it.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;internationalization-i18n&amp;quot;&amp;gt;Internationalization (i18n)&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;&amp;quot;What about translations? My users don&amp;#x27;t all speak English.&amp;quot; Because we&amp;#x27;re just using Valibot, we can use any i18n solution you like. You just pass the translated string (or a function) to the schema.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;pre class=&amp;quot;giallo&amp;quot; style=&amp;quot;color: #C6D0F5; background-color: #303446;&amp;quot;&amp;gt;&amp;lt;code data-lang=&amp;quot;typescript&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;import&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; {&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; t&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt; }&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt; from&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt; &amp;amp;quot;.&amp;#x2F;i18n&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #CA9EE6;&amp;quot;&amp;gt;const&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt; schema&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; object&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;{&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;  password&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt;:&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; pipe&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;    string&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt;    minLength&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #EF9F76;&amp;quot;&amp;gt;8&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;, ()&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #81C8BE;&amp;quot;&amp;gt; =&amp;amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #8CAAEE;font-style: italic;&amp;quot;&amp;gt; t&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;(&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #A6D189;&amp;quot;&amp;gt;&amp;amp;quot;errors.passwordTooShort&amp;amp;quot;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;))&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span&amp;gt;  )&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;,&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;
&amp;lt;span class=&amp;quot;giallo-l&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;}&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span&amp;gt;)&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;span style=&amp;quot;color: #949CBB;&amp;quot;&amp;gt;;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;span&amp;gt;&amp;lt;&amp;#x2F;code&amp;gt;&amp;lt;&amp;#x2F;pre&amp;gt;
&amp;lt;p&amp;gt;The schema is just code. It runs at runtime. So your error messages are always up to date with the user&amp;#x27;s locale.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;why-valibot&amp;quot;&amp;gt;Why Valibot?&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;&amp;quot;Why not Zod?&amp;quot; you ask. &amp;quot;Zod is the standard.&amp;quot; I love Zod. But we&amp;#x27;re already using Valibot for our &amp;lt;a href=&amp;quot;&amp;#x2F;blog&amp;#x2F;schema-first-router&amp;#x2F;&amp;quot;&amp;gt;Schema-First Router&amp;lt;&amp;#x2F;a&amp;gt;. It&amp;#x27;s tiny. It&amp;#x27;s modular. And most importantly, for a library that might end up in a client-side bundle, every kilobyte counts.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;Valibot&amp;#x27;s modular design means you only bundle what you use. For many forms, the validation logic adds less than 1kb to your bundle. While we built this implementation for Valibot to get that tight integration, the &amp;lt;em&amp;gt;pattern&amp;lt;&amp;#x2F;em&amp;gt;—Schema as Source of Truth—works with Zod, ArkType, or any other schema library. We just chose the lightest one.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;h3 id=&amp;quot;related-work&amp;quot;&amp;gt;Related Work&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;We didn&amp;#x27;t build this in a vacuum. We looked at the landscape and learned from the best.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Formik&amp;lt;&amp;#x2F;strong&amp;gt;: The pioneer. It taught us how to handle form state in React.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;react-hook-form&amp;lt;&amp;#x2F;strong&amp;gt;: The gold standard. We love it. But it&amp;#x27;s imperative. You &amp;lt;code&amp;gt;register&amp;lt;&amp;#x2F;code&amp;gt; fields. We wanted to be declarative: you &amp;lt;code&amp;gt;define&amp;lt;&amp;#x2F;code&amp;gt; schemas.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;remix-validated-form&amp;lt;&amp;#x2F;strong&amp;gt;: Very similar philosophy! But tied to Remix. We wanted something that works in any React app (SPA or SSR).&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;auto-form &amp;#x2F; uniforms&amp;lt;&amp;#x2F;strong&amp;gt;: These libraries generate the &amp;lt;em&amp;gt;entire&amp;lt;&amp;#x2F;em&amp;gt; UI for you. We don&amp;#x27;t. We generate the &amp;lt;em&amp;gt;props&amp;lt;&amp;#x2F;em&amp;gt;. You still own the render. You still write the JSX. We just fill in the blanks.&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;&amp;#x2F;ul&amp;gt;
&amp;lt;h2 id=&amp;quot;getting-started&amp;quot;&amp;gt;Getting Started&amp;lt;&amp;#x2F;h2&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a rel=&amp;quot;external&amp;quot; href=&amp;quot;https:&amp;#x2F;&amp;#x2F;docs.werkbank.dev&amp;#x2F;documents&amp;#x2F;Getting_Started.html&amp;quot;&amp;gt;Getting Started&amp;lt;&amp;#x2F;a&amp;gt;&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a rel=&amp;quot;external&amp;quot; href=&amp;quot;https:&amp;#x2F;&amp;#x2F;docs.werkbank.dev&amp;#x2F;documents&amp;#x2F;Getting_Started.Form.html&amp;quot;&amp;gt;Form Guide&amp;lt;&amp;#x2F;a&amp;gt;&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;&amp;#x2F;ul&amp;gt;
&amp;lt;h2 id=&amp;quot;related-post&amp;quot;&amp;gt;Related Post&amp;lt;&amp;#x2F;h2&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;&amp;#x2F;blog&amp;#x2F;building-custom-react-inputs&amp;#x2F;&amp;quot;&amp;gt;Building Custom React Inputs&amp;lt;&amp;#x2F;a&amp;gt;&amp;lt;&amp;#x2F;li&amp;gt;
&amp;lt;&amp;#x2F;ul&amp;gt;
&amp;lt;h3 id=&amp;quot;conclusion&amp;quot;&amp;gt;Conclusion&amp;lt;&amp;#x2F;h3&amp;gt;
&amp;lt;p&amp;gt;I deleted so much code. I deleted manual &amp;lt;code&amp;gt;minLength&amp;lt;&amp;#x2F;code&amp;gt; props. I deleted manual &amp;lt;code&amp;gt;pattern&amp;lt;&amp;#x2F;code&amp;gt; regexes that were copied from StackOverflow. I deleted &amp;lt;code&amp;gt;type=&amp;quot;number&amp;quot;&amp;lt;&amp;#x2F;code&amp;gt; declarations. I just write the schema. And the form follows.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;The &amp;lt;strong&amp;gt;Orchestrator&amp;lt;&amp;#x2F;strong&amp;gt; has done its job. It joins the Router in our suite of schema-first tools. A world where the &amp;quot;Type&amp;quot; isn&amp;#x27;t just a static check—it&amp;#x27;s the engine that drives the application.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;It’s not for everyone. If you love writing boilerplate, you’ll hate this. But if you want to trust your forms again? Stop syncing state. Start defining truth.&amp;lt;&amp;#x2F;p&amp;gt;
</content>
            </entry>
            
        
    
</feed>
