<?xml version="1.0" encoding="UTF-8" standalone="no"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:gd="http://schemas.google.com/g/2005" xmlns:georss="http://www.georss.org/georss" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:thr="http://purl.org/syndication/thread/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-9165069509664255576</atom:id><lastBuildDate>Thu, 18 Jun 2026 07:45:14 +0000</lastBuildDate><category>Business SEO</category><category>Design</category><category>CSS</category><category>SEO</category><category>UI</category><category>PHP</category><category>Tools</category><category>Magento</category><category>javascript</category><category>UX</category><category>Techniques</category><category>Web Design</category><category>Inspiration</category><category>Workflow</category><category>Business</category><category>AI</category><category>Accessibility</category><category>Usability</category><category>User experience</category><category>GEO</category><category>Responsive Web design</category><category>Coding</category><category>asp.net</category><category>shopify</category><category>Apps</category><category>liquid</category><category>Tips</category><category>tutorial</category><category>Wordpress</category><category>c-sharp</category><category>CSS3</category><category>Performance</category><category>API</category><category>HTML</category><category>Amazon</category><category>.NET</category><category>Security</category><category>Resources</category><category>Typography</category><category>guides</category><category>html5</category><category>Communication</category><category>Web Designers</category><category>webdev</category><category>Mobile</category><category>WebDevelopment</category><category>social media</category><category>jQuery</category><category>E-Commerce</category><category>LINUX</category><category>Tutorials</category><category>design patterns</category><category>React</category><category>Frameworks</category><category>MySQL</category><category>optimization</category><category>Designers</category><category>How to</category><category>ML</category><category>content</category><category>Animation</category><category>CMS</category><category>Design Systems</category><category>Testing</category><category>C#</category><category>Freelancing</category><category>Android</category><category>Essentials</category><category>User Research</category><category>Blogging</category><category>Clients</category><category>Java</category><category>mobile technology</category><category>Marketing</category><category>Modern business</category><category>Browsers</category><category>Process</category><category>Security in MVC</category><category>WordPress Themes</category><category>development</category><category>Career</category><category>Case Studies</category><category>Creativity</category><category>Figma</category><category>LLM</category><category>MVC5</category><category>Plugins</category><category>Web Development</category><category>mvc</category><category>Banking</category><category>Code</category><category>Magento Tips &amp; Tricks</category><category>Opinion</category><category>Productivity</category><category>best practices</category><category>cloud</category><category>Headless</category><category>Navigation</category><category>Next.js</category><category>Research</category><category>azure</category><category>cPanel</category><category>google</category><category>web</category><category>website</category><category>windows</category><category>windows azure</category><category>AI marketing</category><category>Ajax</category><category>Apple</category><category>ECommerce</category><category>Interaction</category><category>Networking</category><category>Photoshop</category><category>Product Strategy</category><category>SVG</category><category>User Interface</category><category>how-to</category><category>ipad</category><category>responsive design</category><category>smpf</category><category>Core Web vitals</category><category>Facebook</category><category>News</category><category>Search Engine Optimization</category><category>Teams</category><category>Web Developers</category><category>Websites</category><category>c</category><category>trends</category><category>updates</category><category>Graphic Design</category><category>HTML 5</category><category>IPhone</category><category>Layouts</category><category>Psychology</category><category>Serverless</category><category>Website performance</category><category>algorithm</category><category>cloud computing</category><category>ocr</category><category>traffic</category><category>ASP.NET5</category><category>Active Directory</category><category>Browser</category><category>CSS Basics</category><category>Data Science</category><category>Email</category><category>Encryption</category><category>FOG</category><category>Fonts</category><category>Illustration</category><category>Node.js</category><category>Round-Ups</category><category>WHM</category><category>Web Designs</category><category>best of lists</category><category>cool apps</category><category>free tools</category><category>front-end</category><category>laravel</category><category>linkedin</category><category>python</category><category>strategy</category><category>technology</category><category>tips and tricks</category><category>user interaction</category><category>Branding</category><category>Centos</category><category>Flash</category><category>Freelancers</category><category>General</category><category>Global Web Design</category><category>HR</category><category>JSP</category><category>Logo</category><category>MVP</category><category>Machine learning</category><category>Opinion Column</category><category>SystemDesign</category><category>Technology trends</category><category>UX design</category><category>app</category><category>cross-browser</category><category>free</category><category>mobiles</category><category>salesforce</category><category>sap</category><category>share</category><category>twitter</category><category>web 2.0</category><category>web designer</category><category>webdesign tips</category><category>Animations basics</category><category>Artificial Intelligence</category><category>Bootstrap</category><category>Community</category><category>DevTools</category><category>Drupal</category><category>EWM</category><category>Execution</category><category>Firewalls</category><category>Founders</category><category>IE CSS</category><category>IIS 7.0</category><category>Icons</category><category>Information</category><category>Internal communications</category><category>Internet Explorer</category><category>Jamstack</category><category>Joomla</category><category>Oracle</category><category>ProductManagement</category><category>Programming</category><category>RWD</category><category>Responsive Websites</category><category>Review</category><category>Skills</category><category>Startups</category><category>UBUNTU</category><category>Visual Design</category><category>Website Design</category><category>XSS</category><category>coding tips</category><category>communities</category><category>database</category><category>layout</category><category>memory</category><category>mobile ready website</category><category>samba</category><category>windows 7</category><category>3D</category><category>AI Tools</category><category>Advertising</category><category>Android apps</category><category>Best of Web</category><category>Business Apps</category><category>CSS frameworks</category><category>Classification Model</category><category>Color</category><category>Colors</category><category>Compilation</category><category>Configure WordPress</category><category>Conversions</category><category>Corporate</category><category>Cross Site Scripting Attack</category><category>Cross Site scripting</category><category>Data Visualization</category><category>Design System</category><category>Design Trends</category><category>DevOps</category><category>Digital Marketing</category><category>Education</category><category>Effects</category><category>Errors</category><category>Ethan Marcotte</category><category>Examples and Practices</category><category>Forms</category><category>Framework</category><category>GraphQL</category><category>Great Business Resources</category><category>Humor</category><category>JSF</category><category>MVC6</category><category>Magento Bug Fixes</category><category>Media Queries</category><category>New Technologies</category><category>New Technology</category><category>On Page SEO</category><category>PPC</category><category>Personalization</category><category>Photography</category><category>Project Management</category><category>ProjectManagement</category><category>Redesign</category><category>SOLID</category><category>Showcase</category><category>Solid principles</category><category>Start-Ups</category><category>Windows 2008</category><category>Wireless Techchnology</category><category>access denied</category><category>analytics</category><category>backup</category><category>best windows mobile apps</category><category>business goals</category><category>css3 transition</category><category>debugging</category><category>devices</category><category>freelance</category><category>generator</category><category>http</category><category>imaging</category><category>js</category><category>mac</category><category>mobile application</category><category>models</category><category>productivity Apps</category><category>pytorch</category><category>semantics</category><category>seo friendly</category><category>sharepoint 2010</category><category>sharer</category><category>snapins</category><category>solid principles in .NET</category><category>storage</category><category>themeforest</category><category>vue</category><category>xml</category><category>32 bit drivers</category><category>404</category><category>Active Directory 2008</category><category>Active Injection</category><category>Administration</category><category>Adobe</category><category>Amazon workspaces</category><category>Art</category><category>Articles</category><category>Authentication Provider</category><category>Autonomous AI Agents</category><category>BeyondTheBrowser</category><category>Branding Advertisement</category><category>Business Tools</category><category>CSRF</category><category>Calendar</category><category>Captcha</category><category>Chrome</category><category>ChromeDev</category><category>ChromeDeveloper</category><category>Codes and Scripts</category><category>Computational Thinking</category><category>Conferences</category><category>Cookie Stealing</category><category>Credit cards</category><category>Cross Site Request Forgery</category><category>Customer Experience</category><category>DDOS Attack</category><category>Design patters</category><category>DigitalTransformation</category><category>Docs</category><category>EO</category><category>Eclipse</category><category>Ethics</category><category>Events</category><category>Exim</category><category>Expression Engine</category><category>External Authentication Provider</category><category>Feature Engineering Feature</category><category>Finding Work</category><category>Fireworks</category><category>Front</category><category>FrontEndDevelopment</category><category>Functions</category><category>Future</category><category>Gatsby</category><category>Get Started</category><category>Google SGE</category><category>Guidelines</category><category>HTACCESS</category><category>IE bugs</category><category>Images</category><category>Innovation</category><category>Instagram</category><category>Installation</category><category>Interactivity</category><category>Internet</category><category>Java basics</category><category>Javascript Libraries</category><category>Laboratory</category><category>Language and Communication</category><category>Leadership</category><category>Learning</category><category>LocalStorage</category><category>MSSQL</category><category>Magento 1.7</category><category>Magento Core Hacks</category><category>Mail Manage</category><category>Mail Queues</category><category>Mental Health</category><category>NET</category><category>PPC Beginner</category><category>Passive Injection</category><category>Plesk</category><category>Preprocessors for CSS</category><category>Privacy</category><category>ProductDesign</category><category>Query</category><category>Query-Intent Targeting</category><category>REST</category><category>Roundup</category><category>Ruby on Rails</category><category>SCM</category><category>SMTP</category><category>SQL</category><category>Sass</category><category>Search Engine Optimisation</category><category>Selling Web Design</category><category>Shortcodes</category><category>Social Networking</category><category>Software</category><category>SoftwareDevelopment</category><category>Storytelling</category><category>TV</category><category>Techiques</category><category>Templates</category><category>URL REWRITE</category><category>Virtual Workers</category><category>Visual Studio 2015</category><category>Voice</category><category>Web Components</category><category>Web Design Inspiration</category><category>Web Pro Business</category><category>Web Security</category><category>Web.config</category><category>WebDev2026</category><category>Webmasters</category><category>Website Builder</category><category>Wi-Fi</category><category>Windows Form</category><category>Wolfram|Alpha</category><category>Workshops</category><category>XSS Attack</category><category>apache</category><category>asp</category><category>best iPhone 4S games</category><category>blogs</category><category>clean code</category><category>client</category><category>configuration</category><category>contact form</category><category>conv-neural-network</category><category>crm</category><category>css framework</category><category>deal</category><category>dll</category><category>erp</category><category>exception</category><category>explicit</category><category>exploit</category><category>facebook apps</category><category>fiction</category><category>flipkart</category><category>form</category><category>games</category><category>genetic algorithm</category><category>gif</category><category>github</category><category>gmail</category><category>google+</category><category>handling errors</category><category>headers</category><category>help and support</category><category>html5 browser</category><category>inspiration design</category><category>jailbreak</category><category>jobmarket</category><category>magento 1.5.1</category><category>magentoui</category><category>malloc</category><category>manufacturing</category><category>masterdata</category><category>mobile apps</category><category>mobile development</category><category>mobile first</category><category>mobile payments</category><category>mozilla addons</category><category>offshore outsourcing</category><category>online networking</category><category>outsourcing</category><category>perl script</category><category>png</category><category>pointers</category><category>reactjs</category><category>responsive designs</category><category>responsive website</category><category>revenue</category><category>search engine</category><category>search index</category><category>sharepoint 2010 error</category><category>social media for business</category><category>social media management</category><category>social media strategy</category><category>software delivery strategy</category><category>speed</category><category>supervised learning</category><category>tesseract</category><category>textbox</category><category>tool</category><category>travel</category><category>user centered design</category><category>vision</category><category>vlan</category><category>web applications</category><category>web design tips</category><category>whatsapp</category><category>widgets</category><category>wordpress multisite network</category><category>+1</category><category>2008 AD</category><category>2011 trends</category><category>2026 AI Marketing Tools</category><category>A11y</category><category>AES</category><category>AI Answers</category><category>AI Marketing Tools</category><category>AI&lt;ML</category><category>AIO Guide</category><category>AIReadiness</category><category>AIinHealthcare</category><category>APF</category><category>ARIMA</category><category>ActionResult</category><category>ActiveDirectory</category><category>Add Terms and Conditions</category><category>Adobe Catalyrst</category><category>Advertisement</category><category>Agile</category><category>Amaon</category><category>Android App Development</category><category>Angular</category><category>Angular JS</category><category>Anti-Spam</category><category>Apache lucene</category><category>Apache lucene indexing</category><category>AppsBusinessContent Strategy</category><category>Array</category><category>Automation</category><category>Automation #Leadership</category><category>B2B</category><category>BI</category><category>Backgrounds</category><category>Barcode</category><category>BbPress</category><category>Benefits of Blog</category><category>Best Facebook Apps for iPad</category><category>Best Of</category><category>Big Picture</category><category>BiotechIndustry</category><category>BlackBerry Apps</category><category>Blockchain Uses</category><category>Blockchain in Payment System</category><category>Blogging Benefits</category><category>Blogging Tips</category><category>Blue Color Websites</category><category>Bootable</category><category>Brands as Entities</category><category>BuildInPublic</category><category>Buttons</category><category>By Noupe     Posted in AJAX</category><category>C# 6</category><category>C# 6.0</category><category>C#.Angular</category><category>CAPM</category><category>CIO</category><category>CQS</category><category>CSF</category><category>CSS Grid</category><category>CTO</category><category>Canvas</category><category>Capacity Planning</category><category>Case Studty</category><category>Cell Phones</category><category>Cheat Sheets</category><category>ChromeDeveloperTool</category><category>Clamav</category><category>ClickJacking</category><category>ClickJacking Attack</category><category>ClinicalResearch</category><category>CloudComputing</category><category>CloudCostOptimization</category><category>CloudMigration</category><category>CloudOptimization</category><category>Clubhouse</category><category>Code Review</category><category>Coding TEchniques</category><category>Collection</category><category>Command Query Separation</category><category>ConfigServer</category><category>Configure WordPress Multisite</category><category>Console</category><category>ConsoleTab</category><category>Content Strategy</category><category>Copywriting</category><category>CostOptimization</category><category>Creative Ads</category><category>Custom Error</category><category>Custom Menu</category><category>Custom Tag Helper</category><category>DCPROMO</category><category>Daring Fireball</category><category>DataDrivenHealthcare</category><category>DataManagement</category><category>DataMigration</category><category>Databases</category><category>Debugging Features</category><category>Decision Tree</category><category>Dell N5010</category><category>Design Principles</category><category>DesignPattern</category><category>Designing Stable Interfaces For Streaming Content
UI</category><category>Developer Tools</category><category>DigitalHealth</category><category>Dimensionality reduction</category><category>Discord</category><category>Discussions</category><category>E-Commerce Themes</category><category>E-E-A-T</category><category>EWMjobs</category><category>Ecommerce-Website-Security</category><category>EdgeComputing</category><category>Elmah</category><category>Elmah Session Hijack</category><category>Elmah Session Hijakcking</category><category>Emotional Design</category><category>Enable Terms and Conditions</category><category>Encapsulation</category><category>EnterpriseIT</category><category>Error</category><category>Error Messages WP</category><category>Evaluation</category><category>Evaluation Confusion Matrix</category><category>Evaluation Methods</category><category>Evergreen</category><category>Excel</category><category>Experience Design</category><category>FBA</category><category>FORECASTING ANALYTICS</category><category>Facebook Authentication Provider</category><category>Facebook Designs</category><category>Facebook apps for students</category><category>Feature scaling in machine learning</category><category>Features C# 6</category><category>FinanceTransformation</category><category>Find Clients</category><category>Firefox extension</category><category>Fixes</category><category>Flash Drive</category><category>Flash Mobile</category><category>Fluid Layouts</category><category>Forum</category><category>Foundation5</category><category>Framework Information</category><category>Free Wordpress Plugins</category><category>Free Wordpress Portfolio themes</category><category>Freebies</category><category>Future Perspectives</category><category>GEEO</category><category>GLFW</category><category>GPS</category><category>GenerativeAI</category><category>GeoLocation</category><category>Gini</category><category>Git</category><category>Glossaries</category><category>Google Treats Brands as Entities</category><category>GoogleChrome</category><category>Graphics</category><category>Green Business</category><category>Green Color Websites</category><category>HT</category><category>HTTP requests</category><category>Hamstack</category><category>Hardware problem</category><category>HealthcareAnalytics</category><category>HealthcareData</category><category>Hide Price</category><category>How to Make a Website</category><category>HttpOnly</category><category>HttpOnly Login</category><category>Hugo</category><category>Hybrid</category><category>I</category><category>IE</category><category>IOS App Development</category><category>IT strategy</category><category>ITConsulting</category><category>Ideation</category><category>Illustrator</category><category>Image optimization</category><category>ImageMagick</category><category>Importance of Blog</category><category>Index</category><category>Infographics</category><category>Infrastructure</category><category>InfrastructureManagement</category><category>Insecure Direct Object Reference</category><category>Insecure Object Reference</category><category>Interface Design</category><category>Internationalization</category><category>Interview</category><category>Interviews</category><category>JSON</category><category>Java FAQ</category><category>Javascript basics</category><category>John Gruber</category><category>Keyword Research</category><category>Kids</category><category>LMD</category><category>LSI keywords</category><category>LSP</category><category>Lambda Expression Visual Studio</category><category>Laptop</category><category>Less</category><category>LifeScienceAnalytics</category><category>LifeSciences</category><category>Linkedin groups</category><category>Linux Malware Detect</category><category>Liskov</category><category>Liskov Substitution Principle</category><category>Liskov Substitution Principle in .NET</category><category>Localization</category><category>Localizations</category><category>Login Http</category><category>Logo Design</category><category>MAgent</category><category>MDG</category><category>MDX</category><category>MVC4</category><category>Machine learning Model</category><category>Magento 1.4</category><category>Magento 1.7.0</category><category>Magento 1.7.0.2</category><category>Magento 1.7.x</category><category>Magento Checkout</category><category>Magento Extensions</category><category>Magento Products</category><category>Magento Templates</category><category>Magento Tutorials</category><category>Magento zip plus 4</category><category>Magento zip plus four</category><category>Management Tips</category><category>MarketResearch</category><category>Master Semantic SEO</category><category>Mathematica</category><category>Membership Premium</category><category>Memberships</category><category>Menus/Navigation</category><category>Microsoft</category><category>Middleware</category><category>MiniTab Screen</category><category>ModSecurity</category><category>Model</category><category>Mootools</category><category>Multisite</category><category>MySQ</category><category>Nagento</category><category>Netstat</category><category>Network</category><category>Newsletters</category><category>NextJs</category><category>OCP</category><category>OCP in .NET</category><category>Object Oriented Principles</category><category>Object Reference</category><category>Online Storage</category><category>Only machine administrators are allowed</category><category>Open Closed Principle</category><category>Open Redirection</category><category>Open Redirection Attack</category><category>OpenGL</category><category>Opera</category><category>Over Posting</category><category>Over Posting Attack</category><category>Over Posting Attack MVC</category><category>Overflow</category><category>PANDAS</category><category>PBI</category><category>PHPMyAmin</category><category>PMP</category><category>PMbestpractice</category><category>POS</category><category>POST</category><category>PWA</category><category>Page SEO</category><category>Paypal API</category><category>PerfTip</category><category>Performa</category><category>PharmaAnalytics</category><category>Philosophy</category><category>PhpMyAdmin</category><category>Pine Script</category><category>Pinterest</category><category>Portfolio design</category><category>Power BI</category><category>Print</category><category>Printing</category><category>Product Page</category><category>ProductThinking</category><category>Profiling</category><category>ProgramManagement</category><category>ProjectManager</category><category>Prototypes</category><category>Publishing</category><category>Python Programming</category><category>Quora</category><category>Quote and Comment</category><category>RIM</category><category>RSA</category><category>RSS</category><category>React native</category><category>React native createClass</category><category>React native undefined</category><category>Recruitment</category><category>Redux</category><category>Regression Model</category><category>Remote Access</category><category>Remove Price</category><category>Resource</category><category>Response Header</category><category>Restaurant POS</category><category>Resumes</category><category>Round Tips</category><category>Routing</category><category>Routing Constraints</category><category>SAPSCM</category><category>SAPTransformation</category><category>SAPopportunities</category><category>SCMoppportunities</category><category>SCSS</category><category>SEO Friendly themes</category><category>SEO agency</category><category>SEOBusibness</category><category>SMS Authentication in MVC</category><category>SRP</category><category>SRP in .NET</category><category>Sahrepoint</category><category>Salesforce package install failed</category><category>Schema Markup</category><category>Search</category><category>Search engines</category><category>Secret Manager</category><category>SecretManager</category><category>Secure Object Reference</category><category>Selection Methods</category><category>Sell Your Services</category><category>Sell online</category><category>Selling Web Design Services</category><category>Semantic SEO</category><category>Session Hijack</category><category>Session Hijack Elmah</category><category>Session Hijacking</category><category>Session Hijacking using Elmah</category><category>Share Chat</category><category>SharePoint 2010 Search</category><category>SharePoint search results</category><category>Simple Script Makes Powerfull Count</category><category>Smashing Books</category><category>SoftwareArchitecture .ProjectManagement</category><category>Sprites</category><category>Stack trace</category><category>StartupGrowth</category><category>Static Generators</category><category>Steal Credentials</category><category>Stories</category><category>StringBuffer Class</category><category>Studies</category><category>Surf  with different proxy</category><category>TIME SERIES FORECASTING</category><category>TIME SERIES TIME SERIES ANALYSIS</category><category>Tablets</category><category>Tabs</category><category>Tag Helper</category><category>Tag helper Advantage</category><category>Tax+4</category><category>Teamwork</category><category>TechLeadership</category><category>Technique</category><category>Techniques
Typography</category><category>TempData</category><category>Terms and Conditions</category><category>Texture Based Website</category><category>Themes</category><category>Time savers</category><category>Timeseries</category><category>Timten-AgentParser</category><category>Top Facebook Apps for iPad</category><category>Transitions</category><category>Travel Templates</category><category>Trend</category><category>Tumblr</category><category>Tutoril</category><category>TypeScript</category><category>UX Research</category><category>Unblock</category><category>Unblock Facebook</category><category>Undefined is not an object(evaluating'_react2.default.PropType.bool') react native update react update</category><category>Uploaders</category><category>User Exp</category><category>User Reasearch</category><category>VB.NET Quiz</category><category>VNACloud</category><category>Varien</category><category>Version Information</category><category>Video</category><category>Video Converters</category><category>View</category><category>ViewBag</category><category>ViewData</category><category>ViewModel</category><category>VirtuMart</category><category>Virtual Box</category><category>Virtual Office</category><category>Visual Studio</category><category>Visualization</category><category>Vuew</category><category>WP errors</category><category>Wasm</category><category>Web Designing</category><category>Web Hosting</category><category>Web technologies</category><category>WebAccessibility</category><category>WebAssembly</category><category>WebGL</category><category>Website Designing</category><category>White screen WordPress</category><category>Window XP</category><category>Windows Apps</category><category>Windows Server</category><category>Windows server 2008</category><category>Wireless</category><category>Wolfram Language</category><category>WordPress Ad Plugins</category><category>WordPress Catfish Ads</category><category>WordPress Flyout Ads</category><category>WordPress Membership website</category><category>WordPress network with multiple domains</category><category>WordPress network without subdomains</category><category>Wordpress Amazon S3</category><category>Wordpress Migration to Catalyst</category><category>Wordpress blogs</category><category>Writing</category><category>XSRF</category><category>Xhtml</category><category>YQL</category><category>ZURB Foundation</category><category>Zip+4</category><category>add fields</category><category>adversal machine learning</category><category>adverserial machine learning</category><category>advertise</category><category>advice</category><category>amazon client</category><category>android gps apps</category><category>android vs ios</category><category>antivirus</category><category>application architecture architecture GraphQL gRPC REST</category><category>applications</category><category>appsettings</category><category>arp</category><category>ascii-art</category><category>aslr</category><category>asp dot net</category><category>asp.net development</category><category>asug</category><category>attributes</category><category>auto discounts</category><category>back-end</category><category>bad comment</category><category>barcod</category><category>base64</category><category>bbuffer-overflow</category><category>beautifulsoup</category><category>best iPhone</category><category>bigcommerce</category><category>blockquote</category><category>blogging tools</category><category>books</category><category>browser hacks</category><category>bsod</category><category>buddypress spam</category><category>buddypress spam activity</category><category>buddypress spam plugin</category><category>budget</category><category>buffer</category><category>buffer-overflow</category><category>bufferedwritter</category><category>burgerAPI</category><category>burning</category><category>business applications</category><category>business logic</category><category>business networking site</category><category>business value</category><category>cache</category><category>cdp</category><category>change port mstsc</category><category>change port remote desktop</category><category>change rdc port</category><category>change rdp port</category><category>checklists</category><category>choices</category><category>cloud based app</category><category>cloud workspaces</category><category>code faster</category><category>collaboration</category><category>combine multiple javascripts</category><category>command prompt</category><category>comment</category><category>comment in code</category><category>comments</category><category>compile</category><category>compress</category><category>conda</category><category>conference</category><category>configuration in laravel</category><category>connection strings</category><category>consultants</category><category>contact forms</category><category>conv-neural network</category><category>cookie secure</category><category>cookie security</category><category>cookies</category><category>core dumps</category><category>count line</category><category>cpp</category><category>crash</category><category>crawl using python</category><category>crawl using selenium and python</category><category>ctc</category><category>custom error in web config</category><category>custom fields</category><category>customer value</category><category>cyber law</category><category>d3</category><category>data URIs</category><category>data protection</category><category>debian</category><category>decompilation</category><category>decompilaton</category><category>decryption</category><category>dep</category><category>digg</category><category>digital</category><category>directory traversal</category><category>django</category><category>dnsmasq</category><category>domain</category><category>dot net development</category><category>dutch company logo</category><category>dynamic</category><category>dynamic dacebook</category><category>e-commerce development</category><category>e-commerce web development</category><category>e-commerce webstore</category><category>embed</category><category>empathy</category><category>emulators</category><category>encoding</category><category>encrypted code</category><category>error correction</category><category>esx</category><category>ethernet</category><category>example in python</category><category>exploit scanner</category><category>extensions</category><category>facebook app</category><category>facebook connect</category><category>faceboook</category><category>failed missing organization</category><category>fcgi</category><category>feature</category><category>feature scaling</category><category>feedburner share</category><category>file</category><category>filenotfoundexception</category><category>filewritter</category><category>find fonts used online</category><category>find line count</category><category>flash player</category><category>flowplayer</category><category>form validation post and retain form data laravel</category><category>forms in laravel</category><category>foundation</category><category>free Android gps apps</category><category>free iPhone 4S games</category><category>free windows mobile apps</category><category>free wordpress themes</category><category>from validation laravel</category><category>frontend</category><category>ftp</category><category>giyhub</category><category>gmail extention</category><category>godaddy</category><category>good</category><category>google xml</category><category>graceful degradation</category><category>gradient-descent</category><category>grid Systems</category><category>group policies</category><category>grow</category><category>hana</category><category>headless chrome</category><category>healthcare</category><category>healthcare apps</category><category>hide stack trace</category><category>hosting</category><category>hot-patch</category><category>how to make website</category><category>hp</category><category>htc</category><category>htc explorer</category><category>html5 video plugin</category><category>https</category><category>human resource</category><category>iPhone 4S</category><category>image creator</category><category>image processing</category><category>image slideshow</category><category>install amazon workspaces</category><category>intel-pin</category><category>inter-process-communication</category><category>interfaces</category><category>intimacy</category><category>ios</category><category>ip</category><category>ipad 2 apps</category><category>ipad apps</category><category>ipad.ipad2</category><category>issue in ubuntu</category><category>java collection</category><category>java collection framework</category><category>java collection tutorial</category><category>java collections</category><category>java collections example</category><category>java collections framework</category><category>java example</category><category>java tutorial</category><category>javascript date</category><category>javascript remoting</category><category>javascripts</category><category>job-sites</category><category>jpg</category><category>kernel</category><category>labels</category><category>large file processor</category><category>lazyloading</category><category>learn</category><category>licensing</category><category>lifetime value</category><category>lighning app installation</category><category>linux ubuntu</category><category>linux.</category><category>list</category><category>lldp</category><category>log</category><category>log file parcer</category><category>login</category><category>mac os x</category><category>magento 1.3</category><category>magento 1.8</category><category>magento checkout zip</category><category>magento zip</category><category>magento.ui</category><category>magnto</category><category>make money online</category><category>malicious code</category><category>mangeot</category><category>map</category><category>maps</category><category>material</category><category>matlab</category><category>mean</category><category>menu images</category><category>message</category><category>messenger</category><category>metric</category><category>min-max normalization</category><category>minecraft</category><category>mission</category><category>mobile application tips</category><category>mobile business intelligence</category><category>mobile security</category><category>mobile smart website</category><category>mobile trends</category><category>money</category><category>motog</category><category>msi</category><category>nameserver</category><category>nearest neighbour</category><category>nero</category><category>netbios</category><category>neural network</category><category>neural-network</category><category>neurology</category><category>nodejs</category><category>normalization</category><category>normalization in pandas</category><category>northwest wordpress sites</category><category>nusiness</category><category>oauth2</category><category>ob</category><category>octave</category><category>ogg</category><category>online editors</category><category>online invoice</category><category>online marketing</category><category>online tools</category><category>open source</category><category>optimize</category><category>outsourcing to India</category><category>pacific northwest wordpress</category><category>pagination</category><category>panel</category><category>passing parameter from javascript to controller</category><category>password security</category><category>patch</category><category>payroll management system</category><category>pbis</category><category>performance fix</category><category>performance in java</category><category>performance issue in java</category><category>perl</category><category>perl file parcer</category><category>perl script for count line</category><category>permissions</category><category>phone</category><category>phonegap</category><category>photo gallery</category><category>php.magento</category><category>php8</category><category>phpmagento</category><category>picam</category><category>pinescript</category><category>pixel-art</category><category>popup</category><category>portfolios</category><category>post formats</category><category>prng</category><category>professionalism</category><category>project</category><category>protocol</category><category>proxy</category><category>proxy website</category><category>pscyholopgy</category><category>pwntools</category><category>quotes</category><category>reason for performance</category><category>recaptcha</category><category>reflector</category><category>regex</category><category>registry</category><category>regularexpression</category><category>reinforcement-learning</category><category>remote desktop port  How to change the listening port for RDC/RDP</category><category>remoting</category><category>remoting crud</category><category>rendering</category><category>responsive web designs</category><category>robert martin</category><category>robots.txt</category><category>rpi</category><category>rsync</category><category>ruby</category><category>salesforce issue</category><category>sapcloud</category><category>sapconsultants</category><category>satellite internet</category><category>scraping</category><category>scraping using chrome and selenium</category><category>scraping using python and beautifulsoup</category><category>screenshot</category><category>search engine marketing</category><category>selectors</category><category>server</category><category>services</category><category>servlet</category><category>servlet class</category><category>servlet deploy in tomcat</category><category>servlet example</category><category>servlet tutorial</category><category>set</category><category>set custom error</category><category>set custom error in .net</category><category>setup</category><category>sex</category><category>sharepoint</category><category>shell</category><category>sidebar</category><category>silverlight</category><category>single responsibility principle</category><category>sitemap</category><category>skeleton</category><category>sklearn</category><category>skype</category><category>small business</category><category>smartphones</category><category>smp</category><category>social media automation</category><category>social networking tools</category><category>sockets</category><category>source</category><category>spam</category><category>sql azure</category><category>sql injection</category><category>ssl</category><category>static-analysis</category><category>subscriptions</category><category>suggestion</category><category>supply chain</category><category>svn</category><category>sync</category><category>syntax highlighting</category><category>sysprep</category><category>tac</category><category>tasseract</category><category>tax calculation</category><category>tax not calculated</category><category>tcp</category><category>tech blogging</category><category>tech news</category><category>telegram</category><category>texture pack</category><category>theme authenticity checker</category><category>theme checker</category><category>theora</category><category>thumbnails</category><category>time management</category><category>times ten</category><category>tips to use cloud accounting software</category><category>top performance issue in java</category><category>transactionaldata</category><category>tweaks</category><category>ubunt</category><category>ubuntu login bug</category><category>ubuntu login loop bug</category><category>ultrasurf</category><category>unblock youtube</category><category>unicode</category><category>unix</category><category>unsupervised learning</category><category>unsupervised-learning</category><category>upcoming e-commerce trends</category><category>upgrade</category><category>url</category><category>use LSI keywords</category><category>user interface improvement microsoft</category><category>utf8</category><category>util</category><category>utility</category><category>version control</category><category>vertical align center</category><category>video playlist</category><category>videos</category><category>visualforce page access static resource</category><category>visualforce script remoting</category><category>voip</category><category>volusion</category><category>w3c</category><category>web fonts</category><category>web history</category><category>web marketing</category><category>web standards</category><category>web2 roundups</category><category>webhost security</category><category>website designs</category><category>website headers</category><category>website tools</category><category>websockets</category><category>white blank screen</category><category>why comments bad</category><category>wi-vi technology</category><category>wifi</category><category>windows message</category><category>windows mobile</category><category>windows phone</category><category>wine installation</category><category>wireframing</category><category>wms</category><category>wordpress audio player</category><category>wordpress design</category><category>wordpress help</category><category>wordpress images</category><category>wordpress membership plugin</category><category>wordpress menu</category><category>wordpress multisite registration</category><category>wordpress multisite users</category><category>wordpress plugin</category><category>wordpress plugins</category><category>wordpress showcase</category><category>wordpress video player</category><category>workaholic</category><category>wp to buffer</category><category>yahoo</category><category>yii framework</category><category>youtube to mp3</category><category>youtube videos to mp3</category><category>zip code Magento</category><category>{ine Script</category><category>| search results</category><title>Honey Vig Web Developer Ajax,Jquery, ASP, PHP, dotNET</title><description>Advice, Opinions and Views</description><link>http://honeyvig.blogspot.com/</link><managingEditor>noreply@blogger.com (H)</managingEditor><generator>Blogger</generator><openSearch:totalResults>3414</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><language>en-us</language><itunes:explicit>no</itunes:explicit><itunes:subtitle>Advice, Opinions and Views</itunes:subtitle><itunes:category text="Technology"><itunes:category text="Software How-To"/></itunes:category><itunes:owner><itunes:email>noreply@blogger.com</itunes:email></itunes:owner><item><guid isPermaLink="false">tag:blogger.com,1999:blog-9165069509664255576.post-3471050817046518420</guid><pubDate>Wed, 17 Jun 2026 12:45:02 +0000</pubDate><atom:updated>2026-06-17T05:45:02.132-07:00</atom:updated><title>The Benefits Of Cognitive Inclusion In UX Research</title><description>&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="c-garfield-summary"&gt;&lt;section aria-label="Quick summary" class="article__summary"&gt;Findings
 from an exploratory user research study highlighting the unique 
insights and practical UX recommendations shared by participants with 
cognitive disabilities.&lt;/section&gt;&lt;/div&gt;&lt;p&gt;In the summer of 2024, I 
became co-chair of a working group of expert researchers who came 
together to determine how best to perform accessibility testing with 
people with cognitive disabilities. This was work I did for Fable, where
 I am currently VP of Innovation.&lt;/p&gt;&lt;p&gt;Cognitive disability is an 
umbrella term for several disabilities that impact how people process 
information, and it usually affects memory, focus, and/or learning. It 
is the most prevalent disability in the U.S. (13.9% via &lt;a href="https://www.cdc.gov/disability-and-health/articles-documents/disability-impacts-all-of-us-infographic.html"&gt;CDC&lt;/a&gt;), and cognitive disability is increasing rapidly (&lt;a href="https://news.yale.edu/2025/09/24/growing-number-us-adults-report-cognitive-disability"&gt;Yale study&lt;/a&gt;).&lt;/p&gt;&lt;p&gt;We set four goals for ourselves to learn how to work with this audience:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;How should we recruit and screen participants?&lt;/li&gt;&lt;li&gt;What are best practices for research with cognitive participants?&lt;/li&gt;&lt;li&gt;Do these methods work in a real study?&lt;/li&gt;&lt;li&gt;Documenting what we learned so that we could share it.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;We
 created a screener to recruit people who self-identified as having 
challenges with memory, focus, and learning. We also reviewed published 
studies that involved cognitive testers to learn best practices for 
working with them.&lt;/p&gt;&lt;p&gt;Next, we tested these best practices with an 
initial group of 25 testers in a pilot study. We fine-tuned our approach
 iteratively and created a guide to running user interviews with 
cognitive testers and a survey that could quantify their experiences 
using digital products. Finally, we &lt;a href="https://makeitfable.com/article/cognitive-accessibility-pilot-case-study/"&gt;documented what we learned&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;After
 our pilot study with this new group of testers finished, I felt that 
they would uncover more usability insights than the general population 
(gen pop) user research participants I’d worked with in the past. I set 
out to validate this hunch.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h2 id="the-cognitive-usability-study"&gt;The Cognitive Usability Study&lt;/h2&gt;&lt;p&gt;I
 decided to run a joint study with Fable’s partners at the University of
 California, Irvine, in collaboration with Syed Fatiul Huq and with help
 from Fable researchers Pranav Pidathala, Ali Brown, and Michael Fagan 
to see if my hypothesis about finding more insights with cognitive 
testers proved true or not.&lt;/p&gt;&lt;p&gt;I generated three websites for the 
study using an AI prototyping tool. I wanted three different types of 
sites with different user goals and content so I could test a variety of
 tasks in the study.&lt;/p&gt;&lt;h3 id="table-1-websites-and-tasks-tested"&gt;Table 1: Websites And Tasks Tested&lt;/h3&gt;&lt;table class="tablesaw break-out"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Website&lt;/th&gt;&lt;th&gt;&lt;a href="https://v0-strong-snacks.vercel.app/"&gt;Strong Snacks&lt;/a&gt;&lt;/th&gt;&lt;th&gt;&lt;a href="https://v0-bookstore-nu.vercel.app/"&gt;Turning Pages&lt;/a&gt;&lt;/th&gt;&lt;th&gt;&lt;a href="https://v0-crown-and-comb.vercel.app/"&gt;Crown &amp;amp; Comb&lt;/a&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td data-label="Website"&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/td&gt;&lt;td data-label="&amp;lt;a href=&amp;quot;https://v0-strong-snacks.vercel.app/&amp;quot;&amp;gt;Strong Snacks&amp;lt;/a&amp;gt;"&gt;This
 is a website for three-ingredient high-protein recipes. Recipes can be 
browsed by category (vegan, muscle building, etc.). The site also 
features blog posts about protein and contact information.&lt;/td&gt;&lt;td data-label="&amp;lt;a href=&amp;quot;https://v0-bookstore-nu.vercel.app/&amp;quot;&amp;gt;Turning Pages&amp;lt;/a&amp;gt;"&gt;This
 website is for a bookstore with a catalog of curated reads. It features
 extensive filtering by book genre, a book swiping feature to build a 
profile of likes and dislikes, custom book lists, a shopping cart, and 
checkout.&lt;/td&gt;&lt;td data-label="&amp;lt;a href=&amp;quot;https://v0-crown-and-comb.vercel.app/&amp;quot;&amp;gt;Crown &amp;amp;amp; Comb&amp;lt;/a&amp;gt;"&gt;A
 website for a hair salon that allows you to book appointments and 
consultations online. It has a VIP program and a variety of special 
packages visitors can buy.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td data-label="Website"&gt;&lt;strong&gt;Design&lt;/strong&gt;&lt;/td&gt;&lt;td data-label="&amp;lt;a href=&amp;quot;https://v0-strong-snacks.vercel.app/&amp;quot;&amp;gt;Strong Snacks&amp;lt;/a&amp;gt;"&gt;Simple, brutalist, bright, lots of pictures.&lt;/td&gt;&lt;td data-label="&amp;lt;a href=&amp;quot;https://v0-bookstore-nu.vercel.app/&amp;quot;&amp;gt;Turning Pages&amp;lt;/a&amp;gt;"&gt;Moody, classic, dark, lots of pictures of book covers.&lt;/td&gt;&lt;td data-label="&amp;lt;a href=&amp;quot;https://v0-crown-and-comb.vercel.app/&amp;quot;&amp;gt;Crown &amp;amp;amp; Comb&amp;lt;/a&amp;gt;"&gt;Bold, clean, black and white with bursts of color.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td data-label="Website"&gt;&lt;strong&gt;Content&lt;/strong&gt;&lt;/td&gt;&lt;td data-label="&amp;lt;a href=&amp;quot;https://v0-strong-snacks.vercel.app/&amp;quot;&amp;gt;Strong Snacks&amp;lt;/a&amp;gt;"&gt;Recipes, blog posts.&lt;/td&gt;&lt;td data-label="&amp;lt;a href=&amp;quot;https://v0-bookstore-nu.vercel.app/&amp;quot;&amp;gt;Turning Pages&amp;lt;/a&amp;gt;"&gt;Books and book lists.&lt;/td&gt;&lt;td data-label="&amp;lt;a href=&amp;quot;https://v0-crown-and-comb.vercel.app/&amp;quot;&amp;gt;Crown &amp;amp;amp; Comb&amp;lt;/a&amp;gt;"&gt;Services, experience guide, membership information.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td data-label="Website"&gt;&lt;strong&gt;Key functionality&lt;/strong&gt;&lt;/td&gt;&lt;td data-label="&amp;lt;a href=&amp;quot;https://v0-strong-snacks.vercel.app/&amp;quot;&amp;gt;Strong Snacks&amp;lt;/a&amp;gt;"&gt;Filter by category, newsletter subscription.&lt;/td&gt;&lt;td data-label="&amp;lt;a href=&amp;quot;https://v0-bookstore-nu.vercel.app/&amp;quot;&amp;gt;Turning Pages&amp;lt;/a&amp;gt;"&gt;Shopping cart, book matching, book lists, recommendations.&lt;/td&gt;&lt;td data-label="&amp;lt;a href=&amp;quot;https://v0-crown-and-comb.vercel.app/&amp;quot;&amp;gt;Crown &amp;amp;amp; Comb&amp;lt;/a&amp;gt;"&gt;Appointment booking.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td data-label="Website"&gt;&lt;strong&gt;Tasks&lt;/strong&gt;&lt;/td&gt;&lt;td data-label="&amp;lt;a href=&amp;quot;https://v0-strong-snacks.vercel.app/&amp;quot;&amp;gt;Strong Snacks&amp;lt;/a&amp;gt;"&gt;&lt;ol&gt;&lt;li&gt;Find a recipe for a high-protein snack.&lt;/li&gt;&lt;li&gt;Find a blog about protein and read it.&lt;/li&gt;&lt;li&gt;Find a way to be notified about new recipes and blog posts.&lt;/li&gt;&lt;/ol&gt;&lt;/td&gt;&lt;td data-label="&amp;lt;a href=&amp;quot;https://v0-bookstore-nu.vercel.app/&amp;quot;&amp;gt;Turning Pages&amp;lt;/a&amp;gt;"&gt;&lt;ol&gt;&lt;li&gt;Find the book swiping feature and use it on 10 books.&lt;/li&gt;&lt;li&gt;Find the recommended book list.&lt;/li&gt;&lt;li&gt;Add books from two genres of your choice to cart.&lt;/li&gt;&lt;li&gt;Checkout the books in your cart.&lt;/li&gt;&lt;/ol&gt;&lt;/td&gt;&lt;td data-label="&amp;lt;a href=&amp;quot;https://v0-crown-and-comb.vercel.app/&amp;quot;&amp;gt;Crown &amp;amp;amp; Comb&amp;lt;/a&amp;gt;"&gt;&lt;ol&gt;&lt;li&gt;Find the prices for getting a haircut.&lt;/li&gt;&lt;li&gt;Book a haircut appointment.&lt;/li&gt;&lt;li&gt;Find the price for the bridal package.&lt;/li&gt;&lt;/ol&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;We
 used a single screener with questions about memory, focus, and 
learning, and screened participants into two groups based on whether 
they self-identified as having cognitive challenges or not.&lt;/p&gt;&lt;blockquote&gt;Cognitive
 disability includes neurodiversity. Neurodivergent is an umbrella term 
used to describe people whose brains process information and learn 
differently. It is most commonly used for people who have learning 
disabilities (e.g., Dyslexia), ADHD, and Autism.&lt;/blockquote&gt;&lt;p&gt;We ran 30 user interviews, 10 per website, with an even &lt;sup&gt;5&lt;/sup&gt;⁄&lt;sub&gt;5&lt;/sub&gt;
 split between cognitive and gen pop participants for each website. In 
each session, a participant completed all the tasks for one website 
during an online user interview facilitated by one of the researchers 
involved in the study.&lt;/p&gt;&lt;p&gt;All participants completed an &lt;a href="https://makeitfable.com/accessible-usability-scale/"&gt;Accessible Usability Scale (AUS) survey&lt;/a&gt;
 at the end of their session. This is a free, Creative Commons-licensed 
10-question survey to evaluate the usability of websites and mobile 
apps.&lt;/p&gt;&lt;h2 id="data-analysis-approach"&gt;Data Analysis Approach&lt;/h2&gt;&lt;p&gt;I
 reviewed all the study recordings and transcripts and made note of 
every time a participant raised a concern, question, difficulty, or 
asked a question about how something worked. I counted all of these as 
issues. I also noted where a participant missed something that was part 
of a task, even if they didn’t notice it themselves. I also noted every 
suggestion for improvement made by participants.&lt;/p&gt;&lt;p&gt;Examples of issues found included:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Photo is too tall and requires a lot of scrolling to get to content (noted by participant).&lt;/li&gt;&lt;li&gt;I get no feedback when I like or dislike a book (noted by participant).&lt;/li&gt;&lt;li&gt;Participant missed the required P.O. Box checkbox the first time (observed by me).&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Examples of suggestions included:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;I would like to see a protein comparison in a table.&lt;/li&gt;&lt;li&gt;The “More information” tab should be moved up higher.&lt;/li&gt;&lt;li&gt;I would like more information on how the recommendation list is created.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Issues
 and suggestions were counted once per participant, even if they 
mentioned the same thing twice, but there are, of course, repeat issues 
and suggestions across the different participants. It is expected in UX 
research with multiple participants that you’ll find similar issues with
 each participant, and that is a signal that an issue is a universal 
challenge.&lt;/p&gt;&lt;h2 id="findings-of-the-cognitive-usability-study"&gt;Findings Of The Cognitive Usability Study&lt;/h2&gt;&lt;p&gt;Across the three websites tested:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Cognitive participants identified 197 issues.&lt;/li&gt;&lt;li&gt;Gen pop participants identified 113 issues.&lt;/li&gt;&lt;li&gt;Cognitive participants made 93 suggestions.&lt;/li&gt;&lt;li&gt;Gen pop participants made 54 suggestions.&lt;/li&gt;&lt;li&gt;Cognitive
 participants surfaced more issues related to content, buttons, icons, 
visual elements, and media than gen pop participants.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The 
results aligned with my instincts: participants with cognitive 
disabilities identified 1.8 times more issues and made 1.8 times more 
suggestions than gen pop participants.&lt;/p&gt;&lt;p&gt;Let’s dive deeper into the 
data for each website. Note that an AUS score ranges from 0 to 100, with
 higher numbers representing better usability than lower numbers.&lt;/p&gt;&lt;h3 id="table-2-strong-snacks"&gt;Table 2: Strong Snacks&amp;nbsp;&lt;/h3&gt;&lt;p&gt;This
 site had the simplest design and content of all websites tested in the 
study and accordingly had the lowest overall issues and the highest 
median AUS scores. The data aligns with what you’d expect from an 
easy-to-use and simple website.&lt;/p&gt;&lt;p&gt;On this website, cognitive 
participants found 3.4 more issues and made 2.2 more suggestions on 
average. Their average score of the overall experience was 13.7 points 
lower than that of the gen pop participants.&lt;/p&gt;&lt;table class="tablesaw break-out"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;br /&gt;&lt;/th&gt;&lt;th&gt;Total issues&lt;/th&gt;&lt;th&gt;Average issues&lt;/th&gt;&lt;th&gt;Median issues&lt;/th&gt;&lt;th&gt;Total suggestions&lt;/th&gt;&lt;th&gt;Average suggestions&lt;/th&gt;&lt;th&gt;Median suggestions&lt;/th&gt;&lt;th&gt;Average AUS&lt;/th&gt;&lt;th&gt;Median AUS&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td data-label=""&gt;&lt;strong&gt;Gen pop&lt;/strong&gt;&lt;/td&gt;&lt;td data-label="Total issues"&gt;32&lt;/td&gt;&lt;td data-label="Average issues"&gt;6.4&lt;/td&gt;&lt;td data-label="Median issues"&gt;6&lt;/td&gt;&lt;td data-label="Total suggestions"&gt;13&lt;/td&gt;&lt;td data-label="Average suggestions"&gt;2.6&lt;/td&gt;&lt;td data-label="Median suggestions"&gt;2&lt;/td&gt;&lt;td data-label="Average AUS"&gt;90.5&lt;/td&gt;&lt;td data-label="Median AUS"&gt;97.5&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td data-label=""&gt;&lt;strong&gt;Cognitive&lt;/strong&gt;&lt;/td&gt;&lt;td data-label="Total issues"&gt;49&lt;/td&gt;&lt;td data-label="Average issues"&gt;9.8&lt;/td&gt;&lt;td data-label="Median issues"&gt;9&lt;/td&gt;&lt;td data-label="Total suggestions"&gt;24&lt;/td&gt;&lt;td data-label="Average suggestions"&gt;4.8&lt;/td&gt;&lt;td data-label="Median suggestions"&gt;4&lt;/td&gt;&lt;td data-label="Average AUS"&gt;76.8&lt;/td&gt;&lt;td data-label="Median AUS"&gt;73.0&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;h3 id="table-3-turning-pages"&gt;Table 3: Turning Pages&lt;/h3&gt;&lt;p&gt;This
 was the website with the most varied functionality and the most tasks 
to complete (4), so it’s not surprising that participants found the most
 issues.&lt;/p&gt;&lt;p&gt;Here, cognitive participants found 6 more issues and made
 3.2 more suggestions on average. They also scored the overall 
experience 17.2 points lower than gen pop participants on average.&lt;/p&gt;&lt;table class="tablesaw break-out"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;br /&gt;&lt;/th&gt;&lt;th&gt;Total issues&lt;/th&gt;&lt;th&gt;Average issues&lt;/th&gt;&lt;th&gt;Median issues&lt;/th&gt;&lt;th&gt;Total suggestions&lt;/th&gt;&lt;th&gt;Average suggestions&lt;/th&gt;&lt;th&gt;Median suggestions&lt;/th&gt;&lt;th&gt;Average AUS&lt;/th&gt;&lt;th&gt;Median AUS&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td data-label=""&gt;&lt;strong&gt;Gen pop&lt;/strong&gt;&lt;/td&gt;&lt;td data-label="Total issues"&gt;55&lt;/td&gt;&lt;td data-label="Average issues"&gt;11&lt;/td&gt;&lt;td data-label="Median issues"&gt;10&lt;/td&gt;&lt;td data-label="Total suggestions"&gt;26&lt;/td&gt;&lt;td data-label="Average suggestions"&gt;5.2&lt;/td&gt;&lt;td data-label="Median suggestions"&gt;4&lt;/td&gt;&lt;td data-label="Average AUS"&gt;78.0&lt;/td&gt;&lt;td data-label="Median AUS"&gt;80.0&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td data-label=""&gt;&lt;strong&gt;Cognitive&lt;/strong&gt;&lt;/td&gt;&lt;td data-label="Total issues"&gt;86&lt;/td&gt;&lt;td data-label="Average issues"&gt;17&lt;/td&gt;&lt;td data-label="Median issues"&gt;15&lt;/td&gt;&lt;td data-label="Total suggestions"&gt;42&lt;/td&gt;&lt;td data-label="Average suggestions"&gt;8.4&lt;/td&gt;&lt;td data-label="Median suggestions"&gt;6&lt;/td&gt;&lt;td data-label="Average AUS"&gt;60.8&lt;/td&gt;&lt;td data-label="Median AUS"&gt;58.0&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;h3 id="table-4-crown-comb"&gt;Table 4: Crown &amp;amp; Comb&lt;/h3&gt;&lt;p&gt;This
 website was intentionally designed to be complex, and task 3, finding 
the bridal package, was meant to be extremely difficult to complete.&lt;/p&gt;&lt;p&gt;On
 this last website, cognitive participants on average found 7 more 
issues and made 2.4 more suggestions. Their average score for the 
overall experience was 14.3 points &lt;strong&gt;higher&lt;/strong&gt; than the gen pop participants.&lt;/p&gt;&lt;table class="tablesaw break-out"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;br /&gt;&lt;/th&gt;&lt;th&gt;Total issues&lt;/th&gt;&lt;th&gt;Average issues&lt;/th&gt;&lt;th&gt;Median issues&lt;/th&gt;&lt;th&gt;Total suggestions&lt;/th&gt;&lt;th&gt;Average suggestions&lt;/th&gt;&lt;th&gt;Median suggestions&lt;/th&gt;&lt;th&gt;Average AUS&lt;/th&gt;&lt;th&gt;Median AUS&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td data-label=""&gt;&lt;strong&gt;Gen pop&lt;/strong&gt;&lt;/td&gt;&lt;td data-label="Total issues"&gt;26&lt;/td&gt;&lt;td data-label="Average issues"&gt;5&lt;/td&gt;&lt;td data-label="Median issues"&gt;4&lt;/td&gt;&lt;td data-label="Total suggestions"&gt;15&lt;/td&gt;&lt;td data-label="Average suggestions"&gt;3&lt;/td&gt;&lt;td data-label="Median suggestions"&gt;3&lt;/td&gt;&lt;td data-label="Average AUS"&gt;49.5&lt;/td&gt;&lt;td data-label="Median AUS"&gt;35.0&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td data-label=""&gt;&lt;strong&gt;Cognitive&lt;/strong&gt;&lt;/td&gt;&lt;td data-label="Total issues"&gt;62&lt;/td&gt;&lt;td data-label="Average issues"&gt;12&lt;/td&gt;&lt;td data-label="Median issues"&gt;11&lt;/td&gt;&lt;td data-label="Total suggestions"&gt;27&lt;/td&gt;&lt;td data-label="Average suggestions"&gt;5.4&lt;/td&gt;&lt;td data-label="Median suggestions"&gt;2&lt;/td&gt;&lt;td data-label="Average AUS"&gt;63.8&lt;/td&gt;&lt;td data-label="Median AUS"&gt;68.0&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;Something
 interesting happened with the AUS scores for cognitive and gen pop 
participants in Tables 3 and 4. Cognitive participants scored Crown 
&amp;amp; Comb higher than Turning Pages, but gen pop scored the opposite — 
higher for Turning Pages and lower for Crown &amp;amp; Comb. If I had to 
guess why, I suspect finding more issues on Turning Pages impacted the 
cognitive participants’ perceptions of usability more than the gen pop 
participants’.&lt;/p&gt;&lt;p&gt;The other major difference between the sites, 
outlined in Table 5 below, was that cognitive participants found many 
more issues with buttons and links on Turning Pages and more issues with
 icons and visual elements on Crown &amp;amp; Comb. This suggests to me that
 the interactions being challenging on Turning Pages were a more 
significant challenge than issues with visual elements.&lt;/p&gt;&lt;h3 id="qualitative-findings"&gt;Qualitative Findings&lt;/h3&gt;&lt;p&gt;When it comes to the more qualitative findings, I looked at trends in the types of issues found by both groups of participants.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Cognitive participants&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Were more likely to flag issues with icons or visual elements.&lt;/li&gt;&lt;li&gt;Surfaced problems with content more frequently.&lt;/li&gt;&lt;li&gt;Gave richer qualitative commentary, often explaining why something was hard to find or confusing.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Gen pop participants&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Were less likely to flag conceptual or comprehension barriers.&lt;/li&gt;&lt;li&gt;Gave shorter feedback, often stopping once the task was complete.&lt;/li&gt;&lt;/ul&gt;&lt;h3 id="table-5-number-of-issues-by-category"&gt;Table 5: Number Of Issues By Category&lt;/h3&gt;&lt;p&gt;When
 I grouped issues by category, the following issues surfaced more often 
with cognitive participants: content, buttons and links (affordances and
 function), icons or visual elements, and media (video, animations). 
They nearly tied with gen pop participants on navigation issues (45 vs 
46).&lt;/p&gt;&lt;table class="tablesaw break-out"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;br /&gt;&lt;/th&gt;&lt;th colspan="2"&gt;&lt;strong&gt;Strong Snacks&lt;/strong&gt;&lt;/th&gt;&lt;th colspan="2"&gt;&lt;strong&gt;Turning Pages&lt;/strong&gt;&lt;/th&gt;&lt;th colspan="2"&gt;&lt;strong&gt;Crown &amp;amp; Comb&lt;/strong&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td data-label=""&gt;&lt;strong&gt;Issue category&lt;/strong&gt;&lt;/td&gt;&lt;td data-label="&amp;lt;strong&amp;gt;Strong Snacks&amp;lt;/strong&amp;gt;"&gt;Gen pop&lt;/td&gt;&lt;td data-label="&amp;lt;strong&amp;gt;Turning Pages&amp;lt;/strong&amp;gt;"&gt;Cognitive&lt;/td&gt;&lt;td data-label="&amp;lt;strong&amp;gt;Crown &amp;amp;amp; Comb&amp;lt;/strong&amp;gt;"&gt;Gen pop&lt;/td&gt;&lt;td data-label=""&gt;Cognitive&lt;/td&gt;&lt;td data-label="&amp;lt;strong&amp;gt;Strong Snacks&amp;lt;/strong&amp;gt;"&gt;Gen pop&lt;/td&gt;&lt;td data-label="&amp;lt;strong&amp;gt;Turning Pages&amp;lt;/strong&amp;gt;"&gt;Cognitive&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td data-label="&amp;lt;strong&amp;gt;Crown &amp;amp;amp; Comb&amp;lt;/strong&amp;gt;"&gt;&lt;strong&gt;Content&lt;/strong&gt;&lt;/td&gt;&lt;td data-label=""&gt;11&lt;/td&gt;&lt;td data-label="&amp;lt;strong&amp;gt;Strong Snacks&amp;lt;/strong&amp;gt;"&gt;22&lt;/td&gt;&lt;td data-label="&amp;lt;strong&amp;gt;Turning Pages&amp;lt;/strong&amp;gt;"&gt;11&lt;/td&gt;&lt;td data-label="&amp;lt;strong&amp;gt;Crown &amp;amp;amp; Comb&amp;lt;/strong&amp;gt;"&gt;30&lt;/td&gt;&lt;td data-label=""&gt;23&lt;/td&gt;&lt;td data-label="&amp;lt;strong&amp;gt;Strong Snacks&amp;lt;/strong&amp;gt;"&gt;36&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td data-label="&amp;lt;strong&amp;gt;Turning Pages&amp;lt;/strong&amp;gt;"&gt;&lt;strong&gt;Navigation&lt;/strong&gt;&lt;/td&gt;&lt;td data-label="&amp;lt;strong&amp;gt;Crown &amp;amp;amp; Comb&amp;lt;/strong&amp;gt;"&gt;18&lt;/td&gt;&lt;td data-label=""&gt;22&lt;/td&gt;&lt;td data-label="&amp;lt;strong&amp;gt;Strong Snacks&amp;lt;/strong&amp;gt;"&gt;25&lt;/td&gt;&lt;td data-label="&amp;lt;strong&amp;gt;Turning Pages&amp;lt;/strong&amp;gt;"&gt;17&lt;/td&gt;&lt;td data-label="&amp;lt;strong&amp;gt;Crown &amp;amp;amp; Comb&amp;lt;/strong&amp;gt;"&gt;2&lt;/td&gt;&lt;td data-label=""&gt;7&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td data-label="&amp;lt;strong&amp;gt;Strong Snacks&amp;lt;/strong&amp;gt;"&gt;&lt;strong&gt;Buttons and links&lt;/strong&gt;&lt;/td&gt;&lt;td data-label="&amp;lt;strong&amp;gt;Turning Pages&amp;lt;/strong&amp;gt;"&gt;0&lt;/td&gt;&lt;td data-label="&amp;lt;strong&amp;gt;Crown &amp;amp;amp; Comb&amp;lt;/strong&amp;gt;"&gt;5&lt;/td&gt;&lt;td data-label=""&gt;7&lt;/td&gt;&lt;td data-label="&amp;lt;strong&amp;gt;Strong Snacks&amp;lt;/strong&amp;gt;"&gt;20&lt;/td&gt;&lt;td data-label="&amp;lt;strong&amp;gt;Turning Pages&amp;lt;/strong&amp;gt;"&gt;3&lt;/td&gt;&lt;td data-label="&amp;lt;strong&amp;gt;Crown &amp;amp;amp; Comb&amp;lt;/strong&amp;gt;"&gt;0&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td data-label=""&gt;&lt;strong&gt;Icons or visual elements&lt;/strong&gt;&lt;/td&gt;&lt;td data-label="&amp;lt;strong&amp;gt;Strong Snacks&amp;lt;/strong&amp;gt;"&gt;3&lt;/td&gt;&lt;td data-label="&amp;lt;strong&amp;gt;Turning Pages&amp;lt;/strong&amp;gt;"&gt;16&lt;/td&gt;&lt;td data-label="&amp;lt;strong&amp;gt;Crown &amp;amp;amp; Comb&amp;lt;/strong&amp;gt;"&gt;2&lt;/td&gt;&lt;td data-label=""&gt;3&lt;/td&gt;&lt;td data-label="&amp;lt;strong&amp;gt;Strong Snacks&amp;lt;/strong&amp;gt;"&gt;4&lt;/td&gt;&lt;td data-label="&amp;lt;strong&amp;gt;Turning Pages&amp;lt;/strong&amp;gt;"&gt;23&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td data-label="&amp;lt;strong&amp;gt;Crown &amp;amp;amp; Comb&amp;lt;/strong&amp;gt;"&gt;&lt;strong&gt;Media&lt;/strong&gt;&lt;/td&gt;&lt;td data-label=""&gt;0&lt;/td&gt;&lt;td data-label="&amp;lt;strong&amp;gt;Strong Snacks&amp;lt;/strong&amp;gt;"&gt;2&lt;/td&gt;&lt;td data-label="&amp;lt;strong&amp;gt;Turning Pages&amp;lt;/strong&amp;gt;"&gt;0&lt;/td&gt;&lt;td data-label="&amp;lt;strong&amp;gt;Crown &amp;amp;amp; Comb&amp;lt;/strong&amp;gt;"&gt;1&lt;/td&gt;&lt;td data-label=""&gt;0&lt;/td&gt;&lt;td data-label="&amp;lt;strong&amp;gt;Strong Snacks&amp;lt;/strong&amp;gt;"&gt;0&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;Let’s
 look at the commentary provided by one cognitive participant versus one
 gen pop participant in the Crown &amp;amp; Comb sessions. The cognitive 
participant gave an AUS score of 38, and the gen pop participant gave an
 AUS score of 27.5. I chose to compare these two participants because 
they both gave the lowest scores within their group.&lt;/p&gt;&lt;p&gt;Notice the 
differences in how they described the overall experience in the quotes 
below. The gen pop participant explained it was frustrating and not 
engaging. The cognitive participant felt drained and less able to focus.
 I interpreted the experience as having a more profound impact on the 
cognitive participant’s overall wellbeing.&lt;/p&gt;&lt;blockquote&gt;&lt;strong&gt;Gen pop participant quote&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;“As
 soon as you have a name of a treatment and a little explanation and 
like the duration and the price, as soon as you click onto that, it 
should be that you can interact with that service straight away. And I 
feel like if you're seeing a service repeated on a page multiple times 
and you're still not able to select it, it's really, really frustrating.
 This feels not particularly engaging.”&lt;/blockquote&gt;&lt;blockquote&gt;&lt;strong&gt;Cognitive participant quote&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;“For
 example, like, the mental energy aspect of it, like, sometimes there's,
 like, okay, cookies, and then ads, pop-ups, or maybe the website or 
service has too many options to look through, and maybe I just want 
something that I already know. I have to go through a lot of stuff. It 
makes me, like, feel drained and less able to focus.”&lt;/blockquote&gt;&lt;p&gt;In 
summary, across all 3 websites we tested, participants with cognitive 
accessibility needs identified 197 usability issues, compared with 113 
identified by gen pop participants.&lt;/p&gt;&lt;p&gt;Cognitive participants made 93
 suggestions for improving the user experience, compared with 54 
suggestions by gen pop participants.&lt;/p&gt;&lt;blockquote class="pull-quote"&gt;&lt;p&gt;&lt;a aria-label="Share on Twitter" class="pull-quote__link" href="https://twitter.com/share?text=%0aWhen%20I%20compared%20issues%20and%20suggestions%20across%20both%20groups%20of%20participants,%20it%20turned%20out%20that%20the%20cognitive%20participants%20found%201.8%20times%20more%20issues%20and%20made%201.8%20times%20more%20suggestions%20than%20gen%20pop%20participants.%0a&amp;amp;url=https://smashingmagazine.com%2f2026%2f06%2fbenefits-cognitive-inclusion-ux-research%2f"&gt;When
 I compared issues and suggestions across both groups of participants, 
it turned out that the cognitive participants found 1.8 times more 
issues and made 1.8 times more suggestions than gen pop participants.&lt;/a&gt;&lt;/p&gt;&lt;div class="pull-quote__quotation"&gt;&lt;div class="pull-quote__bg"&gt;&lt;span class="pull-quote__symbol"&gt;“&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;p&gt;Cognitive
 participants surfaced more issues related to content, buttons, icons, 
visual elements, and media than gen pop participants.&lt;/p&gt;&lt;div aria-hidden="true" class="c-friskies-box partners partners__lead partners__lead-place partners__external" data-amount="1" data-audience="non-subscriber" data-remove="true"&gt;&lt;/div&gt;&lt;h2 id="how-cognitive-participants-benefit-ux-research"&gt;How Cognitive Participants Benefit UX Research&lt;/h2&gt;&lt;p&gt;In
 working with cognitive participants for the last few years, I’ve seen 
how they surface cognitive load issues consistently. These issues don’t 
just impact people with cognitive disabilities such as neurodivergence; 
they also impact:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Gen Z who lives in a world of short videos 
optimized for attention-grabbing and struggles to focus on long-form and
 written content.&lt;/li&gt;&lt;li&gt;Seniors who naturally experience cognitive decline as they age and have difficulty with complex interactions, especially online.&lt;/li&gt;&lt;li&gt;Adults
 with jobs and families who are constantly busy, overloaded with 
information, making their attention and focus difficult to grab.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;What
 would I have missed if I hadn’t included cognitive participants, and 
how might that have impacted the business outcomes for these websites?&lt;/p&gt;&lt;h3 id="strong-snacks"&gt;Strong Snacks&lt;/h3&gt;&lt;p&gt;On the &lt;em&gt;Strong Snacks&lt;/em&gt; website, the cognitive participants surfaced:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;They would trust the content more if there were links to the sources of information, such as scientific journals.&lt;/li&gt;&lt;li&gt;The need for more context in headlines to understand what the blog is about.&lt;/li&gt;&lt;li&gt;Lack of clarity of the label “Add-ons.”&lt;/li&gt;&lt;li&gt;Layout
 concerns where recipes for snacks interrupted the main article flow 
instead of being placed in a sidebar with a distinct design.&lt;/li&gt;&lt;li&gt;How ads and animations can distract some users from reading the content.&lt;/li&gt;&lt;/ul&gt;&lt;figure&gt;&lt;a href="https://files.smashing.media/articles/benefits-cognitive-inclusion-ux-research/strong-snacks.png"&gt;&lt;img alt="Strong Snacks website" height="463" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/benefits-cognitive-inclusion-ux-research/strong-snacks.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;Strong Snacks websit.&amp;nbsp;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;These
 are improvements that would give all users more trust in the content 
while also making it easier to read and skim for key content. The 
research findings point towards design best practices, such as not 
having continuous animation and using layout to draw attention to 
different types of content that a senior designer might also point out.&lt;/p&gt;&lt;h3 id="turning-pages"&gt;Turning Pages&lt;/h3&gt;&lt;p&gt;Without
 cognitive participants, we might have missed the more subtle but 
important issues with confusing interactions, such as how the “Add to 
book bag” button worked. They were also confused about where reviews and
 recommendations came from. Both of these issues could decrease a user’s
 trust in the website.&lt;/p&gt;&lt;figure&gt;&lt;a href="https://files.smashing.media/articles/benefits-cognitive-inclusion-ux-research/turning-pages.png"&gt;&lt;img alt="Turning Pages website" height="457" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/benefits-cognitive-inclusion-ux-research/turning-pages.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;Turning Pages website.&amp;nbsp;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;All
 participants surfaced that the book-matching feature was hard to find, 
but the deeper problem the cognitive participants emphasized is that the
 site’s interactions don’t consistently behave in ways that they can 
predict and understand, decreasing their confidence.&lt;/p&gt;&lt;p&gt;Anyone who 
wants to buy a book could benefit from a clear understanding of how to 
add books to a cart and complete the checkout quickly and with no 
ambiguity. Compounded over hundreds or thousands of users, a lack of 
clarity in a purchase flow will lead to lost revenue.&lt;/p&gt;&lt;h3 id="crown-comb"&gt;Crown &amp;amp; Comb&lt;/h3&gt;&lt;p&gt;The &lt;em&gt;Crown &amp;amp; Comb&lt;/em&gt; website in particular highlighted the benefits of having cognitive participants who raised:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Concern around why a service would be “subject to stylist consultation.”&lt;/li&gt;&lt;li&gt;Uncertainty with services that had similar labels but may or may not be the same service.&lt;/li&gt;&lt;li&gt;The importance of choosing a date being early in the flow for booking appointments.&lt;/li&gt;&lt;li&gt;Lack of clarity about when or how they would pay for services.&lt;/li&gt;&lt;/ul&gt;&lt;figure&gt;&lt;a href="https://files.smashing.media/articles/benefits-cognitive-inclusion-ux-research/crown-and-comb.png"&gt;&lt;img alt="Crown &amp;amp; Comb website" height="463" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/benefits-cognitive-inclusion-ux-research/crown-and-comb.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;Crown &amp;amp; Comb website.&amp;nbsp;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;These
 issues likely also affect gen pop participants, but they are more 
likely to muddle through a task with incomplete information. However, 
that can lead to losing customers to a better experience if a competitor
 pops up. Loyalty is often tied to experiences, not just brands, and 
having a poor experience means your customer retention can be weaker.&lt;/p&gt;&lt;p&gt;The
 study showed that finding a bridal package was hard for everyone, but 
the cognitive group showed how that became an accessibility barrier. 
When you combine:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;too much ambiguity,&lt;/li&gt;&lt;li&gt;too many decisions,&lt;/li&gt;&lt;li&gt;too little user feedback, and&lt;/li&gt;&lt;li&gt;too much effort to find something,&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;You
 create a high enough cognitive load that some people will not be able 
to complete the task. In my opinion, this is where usability issues 
start to become accessibility barriers — when they increase cognitive 
load so much that it becomes overwhelming for some users.&lt;/p&gt;&lt;h2 id="key-takeaways"&gt;Key Takeaways&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Include people with cognitive disabilities in user research&lt;/strong&gt;, not just accessibility research.&lt;br /&gt;They
 can surface general usability issues related to content, buttons and 
links, icons or visual elements, and media while also helping you 
understand how your product functions in terms of cognitive load.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Cognitive issues are both usability and accessibility issues.&lt;/strong&gt;&lt;br /&gt;Tasks
 that rely heavily on memory, focus, and decision-making can move along a
 scale from difficult to impossible for some users to complete. That’s 
where usability challenges become accessibility barriers.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Track more than task completion.&lt;/strong&gt;&lt;br /&gt;Ask
 users how they feel, how a task affects their energy, how distractions 
impact their ability to focus, and how easy or hard a task was for them.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Start small and build your cognitive inclusive research practice over time.&lt;/strong&gt;&lt;br /&gt;Even
 a few sessions with people who have cognitive access needs can help you
 better understand how to manage cognitive load for all users.&lt;/li&gt;&lt;/ul&gt;&lt;h2 id="start-incorporating-cognitive-insights-now"&gt;Start Incorporating Cognitive Insights Now&lt;/h2&gt;&lt;p&gt;The
 percentage of people aged 65 and older in America is projected to 
increase from 17% to 25%. By 2060, 1 in 4 Americans will be an older 
adult (&lt;a href="https://www.census.gov/content/dam/Census/library/publications/2020/demo/p25-1144.pdf"&gt;U.S. Census&lt;/a&gt;).
 This is where everyone starts to experience cognitive decline. As the 
aging and cognitive population segment expands, companies will need to 
build for these more complex user needs.&lt;/p&gt;&lt;p&gt;People with cognitive 
access needs are a natural starting point because they will find the 
types of usability issues that UX teams are used to. This could make 
cognitive an easier entry point for inclusive research. Getting insights
 from assistive technology users is still very important, but many teams
 don’t know how to start doing that.&lt;/p&gt;&lt;p&gt;Cognitive accessibility is a 
powerful on-ramp into broader accessibility research and testing. By 
focusing first on cognitive load, clarity, and predictability, we build 
research foundations that make future work on accessibility with screen 
readers, screen magnifiers, and alternative navigation users more 
approachable.&lt;/p&gt;&lt;blockquote&gt;“2 sessions with cognitive users feel like 200 because of the volume of insights we get.”&lt;br /&gt;&lt;br /&gt;—UX Manager at Bell Media&lt;/blockquote&gt;&lt;p&gt;In
 this small exploratory study, participants with cognitive disabilities 
identified 1.8 times more issues and made 1.8 times more suggestions 
than gen pop participants. I’ve seen this type of impact in research 
conducted by Fable customers’ websites that aren’t AI-generated, too.&lt;/p&gt;&lt;blockquote class="pull-quote"&gt;&lt;p&gt;&lt;a aria-label="Share on Twitter" class="pull-quote__link" href="https://twitter.com/share?text=%0aCognitive%20inclusion%20in%20UX%20research%20is%20not%20optional,%20and%20it%e2%80%99s%20not%20just%20about%20accessibility.%20It%e2%80%99s%20how%20UX%20teams%20can%20make%20their%20research%20more%20efficient,%20create%20clearer%20content,%20simpler%20flows,%20and%20ship%20better%20products%20for%20everyone.%0a&amp;amp;url=https://smashingmagazine.com%2f2026%2f06%2fbenefits-cognitive-inclusion-ux-research%2f"&gt;Cognitive
 inclusion in UX research is not optional, and it’s not just about 
accessibility. It’s how UX teams can make their research more efficient,
 create clearer content, simpler flows, and ship better products for 
everyone.&lt;/a&gt;&lt;/p&gt;&lt;div class="pull-quote__quotation"&gt;&lt;div class="pull-quote__bg"&gt;&lt;span class="pull-quote__symbol"&gt;“&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;h2 id="study-limitations"&gt;Study Limitations&lt;/h2&gt;&lt;p&gt;This
 study had a relatively small sample size, so the findings are more 
qualitative than quantitatively validated. Testing was also done on two 
different platforms. Cognitive participant sessions were run using &lt;a href="https://makeitfable.com/accessibility-testing-fable-engage/"&gt;Fable Engage&lt;/a&gt;, and gen pop sessions were run on &lt;a href="https://www.userfeel.com/"&gt;UserFeel&lt;/a&gt;.
 Different platforms with unique participant panels can affect the 
quality of insights and comfort levels with user research participation.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Disclosure:&lt;/strong&gt;
 I work for Fable and chose to use our platform because it was more 
affordable than paying for access to another research platform, allowing
 me to include more participants in the study at a lower cost.&lt;/p&gt;&lt;p&gt;Different
 researchers facilitated the user interviews, which can also affect 
findings, but all sessions used the same task structure and discussion 
guide template, and all were completed online. Even though the sessions 
were facilitated by different researchers, the issue and suggestion 
counts were all done by me to ensure consistency across all websites and
 participants.&lt;/p&gt;&lt;h2 id="resources"&gt;Resources&lt;/h2&gt;&lt;p&gt;I’ve compiled a few useful resources as you begin your cognitive inclusion journey.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;W3C &lt;a href="https://www.w3.org/WAI/WCAG2/supplemental/#cognitiveaccessibilityguidance"&gt;supplemental guidance on cognitive accessibility&lt;/a&gt; and more detailed guidance from the &lt;a href="https://www.w3.org/TR/coga-usable/"&gt;cognitive accessibility task force&lt;/a&gt;&lt;/li&gt;&lt;li&gt;MDN overview of how the core web content accessibility guidelines &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/Guides/Cognitive_accessibility"&gt;map to cognitive accessibility supports&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://makeitfable.com/article/cognitive-accessibility-pilot-case-study/"&gt;Case study: Fable’s cognitive accessibility pilot&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://knowaboutaccessibility.org/2025/07/17/5-simple-fixes-that-make-digital-spaces-calmer-for-neurodivergent-and-all-users/"&gt;5 simple fixes that make digital spaces calmer—for neurodivergent and all users&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://stephaniewalter.design/blog/neurodiversity-and-ux-essential-resources-for-cognitive-accessibility/"&gt;Neurodiversity and UX: Essential Resources for Cognitive Accessibility&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;</description><link>http://honeyvig.blogspot.com/2026/06/the-benefits-of-cognitive-inclusion-in.html</link><author>noreply@blogger.com (H)</author><thr:total>0</thr:total><enclosure length="-1" type="application/pdf" url="https://www.census.gov/content/dam/Census/library/publications/2020/demo/p25-1144.pdf"/><itunes:explicit>no</itunes:explicit><itunes:subtitle>&amp;nbsp;Findings from an exploratory user research study highlighting the unique insights and practical UX recommendations shared by participants with cognitive disabilities. In the summer of 2024, I became co-chair of a working group of expert researchers who came together to determine how best to perform accessibility testing with people with cognitive disabilities. This was work I did for Fable, where I am currently VP of Innovation. Cognitive disability is an umbrella term for several disabilities that impact how people process information, and it usually affects memory, focus, and/or learning. It is the most prevalent disability in the U.S. (13.9% via CDC), and cognitive disability is increasing rapidly (Yale study). We set four goals for ourselves to learn how to work with this audience:How should we recruit and screen participants?What are best practices for research with cognitive participants?Do these methods work in a real study?Documenting what we learned so that we could share it. We created a screener to recruit people who self-identified as having challenges with memory, focus, and learning. We also reviewed published studies that involved cognitive testers to learn best practices for working with them. Next, we tested these best practices with an initial group of 25 testers in a pilot study. We fine-tuned our approach iteratively and created a guide to running user interviews with cognitive testers and a survey that could quantify their experiences using digital products. Finally, we documented what we learned. After our pilot study with this new group of testers finished, I felt that they would uncover more usability insights than the general population (gen pop) user research participants I’d worked with in the past. I set out to validate this hunch. &amp;nbsp;The Cognitive Usability Study I decided to run a joint study with Fable’s partners at the University of California, Irvine, in collaboration with Syed Fatiul Huq and with help from Fable researchers Pranav Pidathala, Ali Brown, and Michael Fagan to see if my hypothesis about finding more insights with cognitive testers proved true or not. I generated three websites for the study using an AI prototyping tool. I wanted three different types of sites with different user goals and content so I could test a variety of tasks in the study.Table 1: Websites And Tasks TestedWebsiteStrong SnacksTurning PagesCrown &amp;amp; CombDescriptionThis is a website for three-ingredient high-protein recipes. Recipes can be browsed by category (vegan, muscle building, etc.). The site also features blog posts about protein and contact information.This website is for a bookstore with a catalog of curated reads. It features extensive filtering by book genre, a book swiping feature to build a profile of likes and dislikes, custom book lists, a shopping cart, and checkout.A website for a hair salon that allows you to book appointments and consultations online. It has a VIP program and a variety of special packages visitors can buy.DesignSimple, brutalist, bright, lots of pictures.Moody, classic, dark, lots of pictures of book covers.Bold, clean, black and white with bursts of color.ContentRecipes, blog posts.Books and book lists.Services, experience guide, membership information.Key functionalityFilter by category, newsletter subscription.Shopping cart, book matching, book lists, recommendations.Appointment booking.TasksFind a recipe for a high-protein snack.Find a blog about protein and read it.Find a way to be notified about new recipes and blog posts.Find the book swiping feature and use it on 10 books.Find the recommended book list.Add books from two genres of your choice to cart.Checkout the books in your cart.Find the prices for getting a haircut.Book a haircut appointment.Find the price for the bridal package. We used a single screener with questions about memory, focus, and learning, and screened participants into two groups based on whether they self-identified as having cognitive challenges or not.Cognitive disability includes neurodiversity. Neurodivergent is an umbrella term used to describe people whose brains process information and learn differently. It is most commonly used for people who have learning disabilities (e.g., Dyslexia), ADHD, and Autism. We ran 30 user interviews, 10 per website, with an even 5⁄5 split between cognitive and gen pop participants for each website. In each session, a participant completed all the tasks for one website during an online user interview facilitated by one of the researchers involved in the study. All participants completed an Accessible Usability Scale (AUS) survey at the end of their session. This is a free, Creative Commons-licensed 10-question survey to evaluate the usability of websites and mobile apps.Data Analysis Approach I reviewed all the study recordings and transcripts and made note of every time a participant raised a concern, question, difficulty, or asked a question about how something worked. I counted all of these as issues. I also noted where a participant missed something that was part of a task, even if they didn’t notice it themselves. I also noted every suggestion for improvement made by participants. Examples of issues found included:Photo is too tall and requires a lot of scrolling to get to content (noted by participant).I get no feedback when I like or dislike a book (noted by participant).Participant missed the required P.O. Box checkbox the first time (observed by me). Examples of suggestions included:I would like to see a protein comparison in a table.The “More information” tab should be moved up higher.I would like more information on how the recommendation list is created. Issues and suggestions were counted once per participant, even if they mentioned the same thing twice, but there are, of course, repeat issues and suggestions across the different participants. It is expected in UX research with multiple participants that you’ll find similar issues with each participant, and that is a signal that an issue is a universal challenge.Findings Of The Cognitive Usability Study Across the three websites tested:Cognitive participants identified 197 issues.Gen pop participants identified 113 issues.Cognitive participants made 93 suggestions.Gen pop participants made 54 suggestions.Cognitive participants surfaced more issues related to content, buttons, icons, visual elements, and media than gen pop participants. The results aligned with my instincts: participants with cognitive disabilities identified 1.8 times more issues and made 1.8 times more suggestions than gen pop participants. Let’s dive deeper into the data for each website. Note that an AUS score ranges from 0 to 100, with higher numbers representing better usability than lower numbers.Table 2: Strong Snacks&amp;nbsp; This site had the simplest design and content of all websites tested in the study and accordingly had the lowest overall issues and the highest median AUS scores. The data aligns with what you’d expect from an easy-to-use and simple website. On this website, cognitive participants found 3.4 more issues and made 2.2 more suggestions on average. Their average score of the overall experience was 13.7 points lower than that of the gen pop participants. Total issuesAverage issuesMedian issuesTotal suggestionsAverage suggestionsMedian suggestionsAverage AUSMedian AUSGen pop326.46132.6290.597.5Cognitive499.89244.8476.873.0Table 3: Turning Pages This was the website with the most varied functionality and the most tasks to complete (4), so it’s not surprising that participants found the most issues. Here, cognitive participants found 6 more issues and made 3.2 more suggestions on average. They also scored the overall experience 17.2 points lower than gen pop participants on average. Total issuesAverage issuesMedian issuesTotal suggestionsAverage suggestionsMedian suggestionsAverage AUSMedian AUSGen pop551110265.2478.080.0Cognitive861715428.4660.858.0Table 4: Crown &amp;amp; Comb This website was intentionally designed to be complex, and task 3, finding the bridal package, was meant to be extremely difficult to complete. On this last website, cognitive participants on average found 7 more issues and made 2.4 more suggestions. Their average score for the overall experience was 14.3 points higher than the gen pop participants. Total issuesAverage issuesMedian issuesTotal suggestionsAverage suggestionsMedian suggestionsAverage AUSMedian AUSGen pop2654153349.535.0Cognitive621211275.4263.868.0 Something interesting happened with the AUS scores for cognitive and gen pop participants in Tables 3 and 4. Cognitive participants scored Crown &amp;amp; Comb higher than Turning Pages, but gen pop scored the opposite — higher for Turning Pages and lower for Crown &amp;amp; Comb. If I had to guess why, I suspect finding more issues on Turning Pages impacted the cognitive participants’ perceptions of usability more than the gen pop participants’. The other major difference between the sites, outlined in Table 5 below, was that cognitive participants found many more issues with buttons and links on Turning Pages and more issues with icons and visual elements on Crown &amp;amp; Comb. This suggests to me that the interactions being challenging on Turning Pages were a more significant challenge than issues with visual elements.Qualitative Findings When it comes to the more qualitative findings, I looked at trends in the types of issues found by both groups of participants. Cognitive participants:Were more likely to flag issues with icons or visual elements.Surfaced problems with content more frequently.Gave richer qualitative commentary, often explaining why something was hard to find or confusing. Gen pop participants:Were less likely to flag conceptual or comprehension barriers.Gave shorter feedback, often stopping once the task was complete.Table 5: Number Of Issues By Category When I grouped issues by category, the following issues surfaced more often with cognitive participants: content, buttons and links (affordances and function), icons or visual elements, and media (video, animations). They nearly tied with gen pop participants on navigation issues (45 vs 46). Strong SnacksTurning PagesCrown &amp;amp; CombIssue categoryGen popCognitiveGen popCognitiveGen popCognitiveContent112211302336Navigation1822251727Buttons and links0572030Icons or visual elements31623423Media020100 Let’s look at the commentary provided by one cognitive participant versus one gen pop participant in the Crown &amp;amp; Comb sessions. The cognitive participant gave an AUS score of 38, and the gen pop participant gave an AUS score of 27.5. I chose to compare these two participants because they both gave the lowest scores within their group. Notice the differences in how they described the overall experience in the quotes below. The gen pop participant explained it was frustrating and not engaging. The cognitive participant felt drained and less able to focus. I interpreted the experience as having a more profound impact on the cognitive participant’s overall wellbeing.Gen pop participant quote “As soon as you have a name of a treatment and a little explanation and like the duration and the price, as soon as you click onto that, it should be that you can interact with that service straight away. And I feel like if you're seeing a service repeated on a page multiple times and you're still not able to select it, it's really, really frustrating. This feels not particularly engaging.”Cognitive participant quote “For example, like, the mental energy aspect of it, like, sometimes there's, like, okay, cookies, and then ads, pop-ups, or maybe the website or service has too many options to look through, and maybe I just want something that I already know. I have to go through a lot of stuff. It makes me, like, feel drained and less able to focus.” In summary, across all 3 websites we tested, participants with cognitive accessibility needs identified 197 usability issues, compared with 113 identified by gen pop participants. Cognitive participants made 93 suggestions for improving the user experience, compared with 54 suggestions by gen pop participants. When I compared issues and suggestions across both groups of participants, it turned out that the cognitive participants found 1.8 times more issues and made 1.8 times more suggestions than gen pop participants.“ Cognitive participants surfaced more issues related to content, buttons, icons, visual elements, and media than gen pop participants.How Cognitive Participants Benefit UX Research In working with cognitive participants for the last few years, I’ve seen how they surface cognitive load issues consistently. These issues don’t just impact people with cognitive disabilities such as neurodivergence; they also impact:Gen Z who lives in a world of short videos optimized for attention-grabbing and struggles to focus on long-form and written content.Seniors who naturally experience cognitive decline as they age and have difficulty with complex interactions, especially online.Adults with jobs and families who are constantly busy, overloaded with information, making their attention and focus difficult to grab. What would I have missed if I hadn’t included cognitive participants, and how might that have impacted the business outcomes for these websites?Strong Snacks On the Strong Snacks website, the cognitive participants surfaced:They would trust the content more if there were links to the sources of information, such as scientific journals.The need for more context in headlines to understand what the blog is about.Lack of clarity of the label “Add-ons.”Layout concerns where recipes for snacks interrupted the main article flow instead of being placed in a sidebar with a distinct design.How ads and animations can distract some users from reading the content.Strong Snacks websit.&amp;nbsp; These are improvements that would give all users more trust in the content while also making it easier to read and skim for key content. The research findings point towards design best practices, such as not having continuous animation and using layout to draw attention to different types of content that a senior designer might also point out.Turning Pages Without cognitive participants, we might have missed the more subtle but important issues with confusing interactions, such as how the “Add to book bag” button worked. They were also confused about where reviews and recommendations came from. Both of these issues could decrease a user’s trust in the website.Turning Pages website.&amp;nbsp; All participants surfaced that the book-matching feature was hard to find, but the deeper problem the cognitive participants emphasized is that the site’s interactions don’t consistently behave in ways that they can predict and understand, decreasing their confidence. Anyone who wants to buy a book could benefit from a clear understanding of how to add books to a cart and complete the checkout quickly and with no ambiguity. Compounded over hundreds or thousands of users, a lack of clarity in a purchase flow will lead to lost revenue.Crown &amp;amp; Comb The Crown &amp;amp; Comb website in particular highlighted the benefits of having cognitive participants who raised:Concern around why a service would be “subject to stylist consultation.”Uncertainty with services that had similar labels but may or may not be the same service.The importance of choosing a date being early in the flow for booking appointments.Lack of clarity about when or how they would pay for services.Crown &amp;amp; Comb website.&amp;nbsp; These issues likely also affect gen pop participants, but they are more likely to muddle through a task with incomplete information. However, that can lead to losing customers to a better experience if a competitor pops up. Loyalty is often tied to experiences, not just brands, and having a poor experience means your customer retention can be weaker. The study showed that finding a bridal package was hard for everyone, but the cognitive group showed how that became an accessibility barrier. When you combine:too much ambiguity,too many decisions,too little user feedback, andtoo much effort to find something, You create a high enough cognitive load that some people will not be able to complete the task. In my opinion, this is where usability issues start to become accessibility barriers — when they increase cognitive load so much that it becomes overwhelming for some users.Key TakeawaysInclude people with cognitive disabilities in user research, not just accessibility research. They can surface general usability issues related to content, buttons and links, icons or visual elements, and media while also helping you understand how your product functions in terms of cognitive load.Cognitive issues are both usability and accessibility issues. Tasks that rely heavily on memory, focus, and decision-making can move along a scale from difficult to impossible for some users to complete. That’s where usability challenges become accessibility barriers.Track more than task completion. Ask users how they feel, how a task affects their energy, how distractions impact their ability to focus, and how easy or hard a task was for them.Start small and build your cognitive inclusive research practice over time. Even a few sessions with people who have cognitive access needs can help you better understand how to manage cognitive load for all users.Start Incorporating Cognitive Insights Now The percentage of people aged 65 and older in America is projected to increase from 17% to 25%. By 2060, 1 in 4 Americans will be an older adult (U.S. Census). This is where everyone starts to experience cognitive decline. As the aging and cognitive population segment expands, companies will need to build for these more complex user needs. People with cognitive access needs are a natural starting point because they will find the types of usability issues that UX teams are used to. This could make cognitive an easier entry point for inclusive research. Getting insights from assistive technology users is still very important, but many teams don’t know how to start doing that. Cognitive accessibility is a powerful on-ramp into broader accessibility research and testing. By focusing first on cognitive load, clarity, and predictability, we build research foundations that make future work on accessibility with screen readers, screen magnifiers, and alternative navigation users more approachable.“2 sessions with cognitive users feel like 200 because of the volume of insights we get.” —UX Manager at Bell Media In this small exploratory study, participants with cognitive disabilities identified 1.8 times more issues and made 1.8 times more suggestions than gen pop participants. I’ve seen this type of impact in research conducted by Fable customers’ websites that aren’t AI-generated, too. Cognitive inclusion in UX research is not optional, and it’s not just about accessibility. It’s how UX teams can make their research more efficient, create clearer content, simpler flows, and ship better products for everyone.“Study Limitations This study had a relatively small sample size, so the findings are more qualitative than quantitatively validated. Testing was also done on two different platforms. Cognitive participant sessions were run using Fable Engage, and gen pop sessions were run on UserFeel. Different platforms with unique participant panels can affect the quality of insights and comfort levels with user research participation. Disclosure: I work for Fable and chose to use our platform because it was more affordable than paying for access to another research platform, allowing me to include more participants in the study at a lower cost. Different researchers facilitated the user interviews, which can also affect findings, but all sessions used the same task structure and discussion guide template, and all were completed online. Even though the sessions were facilitated by different researchers, the issue and suggestion counts were all done by me to ensure consistency across all websites and participants.Resources I’ve compiled a few useful resources as you begin your cognitive inclusion journey.W3C supplemental guidance on cognitive accessibility and more detailed guidance from the cognitive accessibility task forceMDN overview of how the core web content accessibility guidelines map to cognitive accessibility supportsCase study: Fable’s cognitive accessibility pilot5 simple fixes that make digital spaces calmer—for neurodivergent and all usersNeurodiversity and UX: Essential Resources for Cognitive Accessibility</itunes:subtitle><itunes:author>noreply@blogger.com (H)</itunes:author><itunes:summary>&amp;nbsp;Findings from an exploratory user research study highlighting the unique insights and practical UX recommendations shared by participants with cognitive disabilities. In the summer of 2024, I became co-chair of a working group of expert researchers who came together to determine how best to perform accessibility testing with people with cognitive disabilities. This was work I did for Fable, where I am currently VP of Innovation. Cognitive disability is an umbrella term for several disabilities that impact how people process information, and it usually affects memory, focus, and/or learning. It is the most prevalent disability in the U.S. (13.9% via CDC), and cognitive disability is increasing rapidly (Yale study). We set four goals for ourselves to learn how to work with this audience:How should we recruit and screen participants?What are best practices for research with cognitive participants?Do these methods work in a real study?Documenting what we learned so that we could share it. We created a screener to recruit people who self-identified as having challenges with memory, focus, and learning. We also reviewed published studies that involved cognitive testers to learn best practices for working with them. Next, we tested these best practices with an initial group of 25 testers in a pilot study. We fine-tuned our approach iteratively and created a guide to running user interviews with cognitive testers and a survey that could quantify their experiences using digital products. Finally, we documented what we learned. After our pilot study with this new group of testers finished, I felt that they would uncover more usability insights than the general population (gen pop) user research participants I’d worked with in the past. I set out to validate this hunch. &amp;nbsp;The Cognitive Usability Study I decided to run a joint study with Fable’s partners at the University of California, Irvine, in collaboration with Syed Fatiul Huq and with help from Fable researchers Pranav Pidathala, Ali Brown, and Michael Fagan to see if my hypothesis about finding more insights with cognitive testers proved true or not. I generated three websites for the study using an AI prototyping tool. I wanted three different types of sites with different user goals and content so I could test a variety of tasks in the study.Table 1: Websites And Tasks TestedWebsiteStrong SnacksTurning PagesCrown &amp;amp; CombDescriptionThis is a website for three-ingredient high-protein recipes. Recipes can be browsed by category (vegan, muscle building, etc.). The site also features blog posts about protein and contact information.This website is for a bookstore with a catalog of curated reads. It features extensive filtering by book genre, a book swiping feature to build a profile of likes and dislikes, custom book lists, a shopping cart, and checkout.A website for a hair salon that allows you to book appointments and consultations online. It has a VIP program and a variety of special packages visitors can buy.DesignSimple, brutalist, bright, lots of pictures.Moody, classic, dark, lots of pictures of book covers.Bold, clean, black and white with bursts of color.ContentRecipes, blog posts.Books and book lists.Services, experience guide, membership information.Key functionalityFilter by category, newsletter subscription.Shopping cart, book matching, book lists, recommendations.Appointment booking.TasksFind a recipe for a high-protein snack.Find a blog about protein and read it.Find a way to be notified about new recipes and blog posts.Find the book swiping feature and use it on 10 books.Find the recommended book list.Add books from two genres of your choice to cart.Checkout the books in your cart.Find the prices for getting a haircut.Book a haircut appointment.Find the price for the bridal package. We used a single screener with questions about memory, focus, and learning, and screened participants into two groups based on whether they self-identified as having cognitive challenges or not.Cognitive disability includes neurodiversity. Neurodivergent is an umbrella term used to describe people whose brains process information and learn differently. It is most commonly used for people who have learning disabilities (e.g., Dyslexia), ADHD, and Autism. We ran 30 user interviews, 10 per website, with an even 5⁄5 split between cognitive and gen pop participants for each website. In each session, a participant completed all the tasks for one website during an online user interview facilitated by one of the researchers involved in the study. All participants completed an Accessible Usability Scale (AUS) survey at the end of their session. This is a free, Creative Commons-licensed 10-question survey to evaluate the usability of websites and mobile apps.Data Analysis Approach I reviewed all the study recordings and transcripts and made note of every time a participant raised a concern, question, difficulty, or asked a question about how something worked. I counted all of these as issues. I also noted where a participant missed something that was part of a task, even if they didn’t notice it themselves. I also noted every suggestion for improvement made by participants. Examples of issues found included:Photo is too tall and requires a lot of scrolling to get to content (noted by participant).I get no feedback when I like or dislike a book (noted by participant).Participant missed the required P.O. Box checkbox the first time (observed by me). Examples of suggestions included:I would like to see a protein comparison in a table.The “More information” tab should be moved up higher.I would like more information on how the recommendation list is created. Issues and suggestions were counted once per participant, even if they mentioned the same thing twice, but there are, of course, repeat issues and suggestions across the different participants. It is expected in UX research with multiple participants that you’ll find similar issues with each participant, and that is a signal that an issue is a universal challenge.Findings Of The Cognitive Usability Study Across the three websites tested:Cognitive participants identified 197 issues.Gen pop participants identified 113 issues.Cognitive participants made 93 suggestions.Gen pop participants made 54 suggestions.Cognitive participants surfaced more issues related to content, buttons, icons, visual elements, and media than gen pop participants. The results aligned with my instincts: participants with cognitive disabilities identified 1.8 times more issues and made 1.8 times more suggestions than gen pop participants. Let’s dive deeper into the data for each website. Note that an AUS score ranges from 0 to 100, with higher numbers representing better usability than lower numbers.Table 2: Strong Snacks&amp;nbsp; This site had the simplest design and content of all websites tested in the study and accordingly had the lowest overall issues and the highest median AUS scores. The data aligns with what you’d expect from an easy-to-use and simple website. On this website, cognitive participants found 3.4 more issues and made 2.2 more suggestions on average. Their average score of the overall experience was 13.7 points lower than that of the gen pop participants. Total issuesAverage issuesMedian issuesTotal suggestionsAverage suggestionsMedian suggestionsAverage AUSMedian AUSGen pop326.46132.6290.597.5Cognitive499.89244.8476.873.0Table 3: Turning Pages This was the website with the most varied functionality and the most tasks to complete (4), so it’s not surprising that participants found the most issues. Here, cognitive participants found 6 more issues and made 3.2 more suggestions on average. They also scored the overall experience 17.2 points lower than gen pop participants on average. Total issuesAverage issuesMedian issuesTotal suggestionsAverage suggestionsMedian suggestionsAverage AUSMedian AUSGen pop551110265.2478.080.0Cognitive861715428.4660.858.0Table 4: Crown &amp;amp; Comb This website was intentionally designed to be complex, and task 3, finding the bridal package, was meant to be extremely difficult to complete. On this last website, cognitive participants on average found 7 more issues and made 2.4 more suggestions. Their average score for the overall experience was 14.3 points higher than the gen pop participants. Total issuesAverage issuesMedian issuesTotal suggestionsAverage suggestionsMedian suggestionsAverage AUSMedian AUSGen pop2654153349.535.0Cognitive621211275.4263.868.0 Something interesting happened with the AUS scores for cognitive and gen pop participants in Tables 3 and 4. Cognitive participants scored Crown &amp;amp; Comb higher than Turning Pages, but gen pop scored the opposite — higher for Turning Pages and lower for Crown &amp;amp; Comb. If I had to guess why, I suspect finding more issues on Turning Pages impacted the cognitive participants’ perceptions of usability more than the gen pop participants’. The other major difference between the sites, outlined in Table 5 below, was that cognitive participants found many more issues with buttons and links on Turning Pages and more issues with icons and visual elements on Crown &amp;amp; Comb. This suggests to me that the interactions being challenging on Turning Pages were a more significant challenge than issues with visual elements.Qualitative Findings When it comes to the more qualitative findings, I looked at trends in the types of issues found by both groups of participants. Cognitive participants:Were more likely to flag issues with icons or visual elements.Surfaced problems with content more frequently.Gave richer qualitative commentary, often explaining why something was hard to find or confusing. Gen pop participants:Were less likely to flag conceptual or comprehension barriers.Gave shorter feedback, often stopping once the task was complete.Table 5: Number Of Issues By Category When I grouped issues by category, the following issues surfaced more often with cognitive participants: content, buttons and links (affordances and function), icons or visual elements, and media (video, animations). They nearly tied with gen pop participants on navigation issues (45 vs 46). Strong SnacksTurning PagesCrown &amp;amp; CombIssue categoryGen popCognitiveGen popCognitiveGen popCognitiveContent112211302336Navigation1822251727Buttons and links0572030Icons or visual elements31623423Media020100 Let’s look at the commentary provided by one cognitive participant versus one gen pop participant in the Crown &amp;amp; Comb sessions. The cognitive participant gave an AUS score of 38, and the gen pop participant gave an AUS score of 27.5. I chose to compare these two participants because they both gave the lowest scores within their group. Notice the differences in how they described the overall experience in the quotes below. The gen pop participant explained it was frustrating and not engaging. The cognitive participant felt drained and less able to focus. I interpreted the experience as having a more profound impact on the cognitive participant’s overall wellbeing.Gen pop participant quote “As soon as you have a name of a treatment and a little explanation and like the duration and the price, as soon as you click onto that, it should be that you can interact with that service straight away. And I feel like if you're seeing a service repeated on a page multiple times and you're still not able to select it, it's really, really frustrating. This feels not particularly engaging.”Cognitive participant quote “For example, like, the mental energy aspect of it, like, sometimes there's, like, okay, cookies, and then ads, pop-ups, or maybe the website or service has too many options to look through, and maybe I just want something that I already know. I have to go through a lot of stuff. It makes me, like, feel drained and less able to focus.” In summary, across all 3 websites we tested, participants with cognitive accessibility needs identified 197 usability issues, compared with 113 identified by gen pop participants. Cognitive participants made 93 suggestions for improving the user experience, compared with 54 suggestions by gen pop participants. When I compared issues and suggestions across both groups of participants, it turned out that the cognitive participants found 1.8 times more issues and made 1.8 times more suggestions than gen pop participants.“ Cognitive participants surfaced more issues related to content, buttons, icons, visual elements, and media than gen pop participants.How Cognitive Participants Benefit UX Research In working with cognitive participants for the last few years, I’ve seen how they surface cognitive load issues consistently. These issues don’t just impact people with cognitive disabilities such as neurodivergence; they also impact:Gen Z who lives in a world of short videos optimized for attention-grabbing and struggles to focus on long-form and written content.Seniors who naturally experience cognitive decline as they age and have difficulty with complex interactions, especially online.Adults with jobs and families who are constantly busy, overloaded with information, making their attention and focus difficult to grab. What would I have missed if I hadn’t included cognitive participants, and how might that have impacted the business outcomes for these websites?Strong Snacks On the Strong Snacks website, the cognitive participants surfaced:They would trust the content more if there were links to the sources of information, such as scientific journals.The need for more context in headlines to understand what the blog is about.Lack of clarity of the label “Add-ons.”Layout concerns where recipes for snacks interrupted the main article flow instead of being placed in a sidebar with a distinct design.How ads and animations can distract some users from reading the content.Strong Snacks websit.&amp;nbsp; These are improvements that would give all users more trust in the content while also making it easier to read and skim for key content. The research findings point towards design best practices, such as not having continuous animation and using layout to draw attention to different types of content that a senior designer might also point out.Turning Pages Without cognitive participants, we might have missed the more subtle but important issues with confusing interactions, such as how the “Add to book bag” button worked. They were also confused about where reviews and recommendations came from. Both of these issues could decrease a user’s trust in the website.Turning Pages website.&amp;nbsp; All participants surfaced that the book-matching feature was hard to find, but the deeper problem the cognitive participants emphasized is that the site’s interactions don’t consistently behave in ways that they can predict and understand, decreasing their confidence. Anyone who wants to buy a book could benefit from a clear understanding of how to add books to a cart and complete the checkout quickly and with no ambiguity. Compounded over hundreds or thousands of users, a lack of clarity in a purchase flow will lead to lost revenue.Crown &amp;amp; Comb The Crown &amp;amp; Comb website in particular highlighted the benefits of having cognitive participants who raised:Concern around why a service would be “subject to stylist consultation.”Uncertainty with services that had similar labels but may or may not be the same service.The importance of choosing a date being early in the flow for booking appointments.Lack of clarity about when or how they would pay for services.Crown &amp;amp; Comb website.&amp;nbsp; These issues likely also affect gen pop participants, but they are more likely to muddle through a task with incomplete information. However, that can lead to losing customers to a better experience if a competitor pops up. Loyalty is often tied to experiences, not just brands, and having a poor experience means your customer retention can be weaker. The study showed that finding a bridal package was hard for everyone, but the cognitive group showed how that became an accessibility barrier. When you combine:too much ambiguity,too many decisions,too little user feedback, andtoo much effort to find something, You create a high enough cognitive load that some people will not be able to complete the task. In my opinion, this is where usability issues start to become accessibility barriers — when they increase cognitive load so much that it becomes overwhelming for some users.Key TakeawaysInclude people with cognitive disabilities in user research, not just accessibility research. They can surface general usability issues related to content, buttons and links, icons or visual elements, and media while also helping you understand how your product functions in terms of cognitive load.Cognitive issues are both usability and accessibility issues. Tasks that rely heavily on memory, focus, and decision-making can move along a scale from difficult to impossible for some users to complete. That’s where usability challenges become accessibility barriers.Track more than task completion. Ask users how they feel, how a task affects their energy, how distractions impact their ability to focus, and how easy or hard a task was for them.Start small and build your cognitive inclusive research practice over time. Even a few sessions with people who have cognitive access needs can help you better understand how to manage cognitive load for all users.Start Incorporating Cognitive Insights Now The percentage of people aged 65 and older in America is projected to increase from 17% to 25%. By 2060, 1 in 4 Americans will be an older adult (U.S. Census). This is where everyone starts to experience cognitive decline. As the aging and cognitive population segment expands, companies will need to build for these more complex user needs. People with cognitive access needs are a natural starting point because they will find the types of usability issues that UX teams are used to. This could make cognitive an easier entry point for inclusive research. Getting insights from assistive technology users is still very important, but many teams don’t know how to start doing that. Cognitive accessibility is a powerful on-ramp into broader accessibility research and testing. By focusing first on cognitive load, clarity, and predictability, we build research foundations that make future work on accessibility with screen readers, screen magnifiers, and alternative navigation users more approachable.“2 sessions with cognitive users feel like 200 because of the volume of insights we get.” —UX Manager at Bell Media In this small exploratory study, participants with cognitive disabilities identified 1.8 times more issues and made 1.8 times more suggestions than gen pop participants. I’ve seen this type of impact in research conducted by Fable customers’ websites that aren’t AI-generated, too. Cognitive inclusion in UX research is not optional, and it’s not just about accessibility. It’s how UX teams can make their research more efficient, create clearer content, simpler flows, and ship better products for everyone.“Study Limitations This study had a relatively small sample size, so the findings are more qualitative than quantitatively validated. Testing was also done on two different platforms. Cognitive participant sessions were run using Fable Engage, and gen pop sessions were run on UserFeel. Different platforms with unique participant panels can affect the quality of insights and comfort levels with user research participation. Disclosure: I work for Fable and chose to use our platform because it was more affordable than paying for access to another research platform, allowing me to include more participants in the study at a lower cost. Different researchers facilitated the user interviews, which can also affect findings, but all sessions used the same task structure and discussion guide template, and all were completed online. Even though the sessions were facilitated by different researchers, the issue and suggestion counts were all done by me to ensure consistency across all websites and participants.Resources I’ve compiled a few useful resources as you begin your cognitive inclusion journey.W3C supplemental guidance on cognitive accessibility and more detailed guidance from the cognitive accessibility task forceMDN overview of how the core web content accessibility guidelines map to cognitive accessibility supportsCase study: Fable’s cognitive accessibility pilot5 simple fixes that make digital spaces calmer—for neurodivergent and all usersNeurodiversity and UX: Essential Resources for Cognitive Accessibility</itunes:summary></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-9165069509664255576.post-2277841665938073208</guid><pubDate>Mon, 15 Jun 2026 08:16:03 +0000</pubDate><atom:updated>2026-06-15T01:19:49.532-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">AI</category><category domain="http://www.blogger.com/atom/ns#">Automation</category><category domain="http://www.blogger.com/atom/ns#">Inspiration</category><category domain="http://www.blogger.com/atom/ns#">Opinion Column</category><title>The Impact Of Humanoid Robots On Humanity</title><description>&lt;p&gt;&amp;nbsp;&lt;span face="Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif" style="caret-color: rgb(51, 51, 51); color: #666666; font-size: 1.15em; font-style: italic;"&gt;We have officially moved past the era of humanoid robots as mere public relations stunts. As they become increasingly lifelike, society may soon face profound social, psychological, and ethical challenges. What happens when the boundary between humans and machines becomes almost impossible to distinguish?&lt;/span&gt;&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 1.1em; grid-column-end: 13; grid-column-start: 3; line-height: 1.55em; margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;For decades, science fiction has cushioned us with the idea that the “android revolution” was a distant fantasy. But the reality is unfolding rapidly. As the line between human and machine blurs, we are forced to confront an impending psychological, economic, and existential shift.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;I recently felt very disturbed after watching a&amp;nbsp;&lt;a href="https://youtube.com/shorts/Iu6eL03BFsc?si=RjFb3dt4Euys3ZCV" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;YouTube video showcasing a humanoid robot&lt;/a&gt;&amp;nbsp;that looked and acted with uncanny realism. While a closer look revealed the video was actually a clever trick, the robot had been swapped for a human actor when the presenter’s back was turned. However, the illusion itself raised a real and unsettling question: Will future androids become so lifelike that we will struggle to tell them apart from our fellow humans? And if so, what does that mean for society? It forces us to ask just how close we are to that threshold, and whether we are ready for the day that science fiction becomes reality.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;What happens when our world is populated by entities that mirror us perfectly, but possess none of our biological history?&lt;/p&gt;&lt;figure style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 679.765625px;"&gt;&lt;a href="https://youtube.com/shorts/Iu6eL03BFsc?si=RjFb3dt4Euys3ZCV" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="Humanoid robot" decoding="async" fetchpriority="low" height="753" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/impact-humanoid-robots-humanity/ai-robot.jpg" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/impact-humanoid-robots-humanity/ai-robot.jpg 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/impact-humanoid-robots-humanity/ai-robot.jpg 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/impact-humanoid-robots-humanity/ai-robot.jpg 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/impact-humanoid-robots-humanity/ai-robot.jpg 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/impact-humanoid-robots-humanity/ai-robot.jpg 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; padding: 0.75em 2em 0.75em 0px;"&gt;How real does this look? (Video source:&amp;nbsp;&lt;a href="https://youtube.com/shorts/Iu6eL03BFsc?si=RjFb3dt4Euys3ZCV" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;YouTube&lt;/a&gt;) (&lt;a href="https://files.smashing.media/articles/impact-humanoid-robots-humanity/ai-robot.jpg" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;h2 id="the-landscape-today" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;The Landscape Today&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;We have officially moved past the era of humanoids as mere public relations stunts. In the past, robots like&amp;nbsp;&lt;a href="https://global.honda/en/newsroom/news/2000/c001120b-eng.html" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Honda’s ASIMO&lt;/a&gt;&amp;nbsp;or early research prototypes were celebrated simply for being able to walk up a flight of stairs without falling over. Today, the technological convergence of advanced electromechanical engineering and artificial intelligence has fundamentally altered the trajectory of robotics.&lt;/p&gt;&lt;figure style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 679.765625px;"&gt;&lt;a href="https://files.smashing.media/articles/impact-humanoid-robots-humanity/honda-asimo-robot.png" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="Honda ASIMO robot" decoding="async" fetchpriority="low" height="715" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/impact-humanoid-robots-humanity/honda-asimo-robot.png" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/impact-humanoid-robots-humanity/honda-asimo-robot.png 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/impact-humanoid-robots-humanity/honda-asimo-robot.png 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/impact-humanoid-robots-humanity/honda-asimo-robot.png 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/impact-humanoid-robots-humanity/honda-asimo-robot.png 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/impact-humanoid-robots-humanity/honda-asimo-robot.png 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; padding: 0.75em 2em 0.75em 0px;"&gt;The&amp;nbsp;&lt;a href="https://global.honda/en/newsroom/news/2000/c001120b-eng.html" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Honda ASIMO robot&lt;/a&gt;&amp;nbsp;back in November 2000.&amp;nbsp;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The current state of the art is defined by an&amp;nbsp;&lt;a href="https://www.researchandmarkets.com/report/humanoid-robot#:~:text=The%20global%20humanoid%20robots%20market%20is%20transitioning,and%20logistics.%20Investment%20momentum%20continues%20to%20intensify." style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;aggressive race toward commercial, physical deployment&lt;/a&gt;. Companies like Figure AI have moved from laboratory demonstrations to active factory floors. Their Figure 02 model completed a&amp;nbsp;&lt;a href="https://www.figure.ai/news/production-at-bmw" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;multi-month deployment at BMW’s Spartanburg plant&lt;/a&gt;, actively contributing to the production of over 30,000 vehicles by handling complex sheet metal components. Meanwhile, Tesla is testing its&amp;nbsp;&lt;a href="https://www.greendrive-accessories.com/blog/language/en/tesla-optimus-3-robot-humanoide-2026-2/#:~:text=Tesla%20is%20already%20using%20early%20versions%20of,accelerate%20the%20robot's%20learning%20through%20reinforcement%20learning." style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Optimus humanoids&lt;/a&gt;&amp;nbsp;inside its own Gigafactories, preparing for mass industrial scale.&lt;/p&gt;&lt;figure style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 679.765625px;"&gt;&lt;a href="https://files.smashing.media/articles/impact-humanoid-robots-humanity/bmw-robot.jpg" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="Robots at BMW production" decoding="async" fetchpriority="low" height="533" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/impact-humanoid-robots-humanity/bmw-robot.jpg" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/impact-humanoid-robots-humanity/bmw-robot.jpg 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/impact-humanoid-robots-humanity/bmw-robot.jpg 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/impact-humanoid-robots-humanity/bmw-robot.jpg 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/impact-humanoid-robots-humanity/bmw-robot.jpg 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/impact-humanoid-robots-humanity/bmw-robot.jpg 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; padding: 0.75em 2em 0.75em 0px;"&gt;&lt;a href="https://www.figure.ai/news/production-at-bmw" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Figure AI robots&lt;/a&gt;&amp;nbsp;are helping to build cars.&amp;nbsp;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;What truly separates today’s humanoid robots from older generations isn’t just how well they move but how they “think.” In the past, a robot needed millions of lines of strict, unchangeable code just to perform a single, simple task. Today, thanks to the explosion of advanced Artificial Intelligence, robots are powered by “brains” built on cutting-edge software like&amp;nbsp;&lt;a href="https://en.wikipedia.org/wiki/Figure_AI" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Figure AI’s Helix&lt;/a&gt;&amp;nbsp;or&amp;nbsp;&lt;a href="https://kraneshares.com/humanoid-robotics-in-2026-the-race-from-pilot-to-platform/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;NVIDIA’s GR00T&lt;/a&gt;. Instead of being meticulously programmed, these&amp;nbsp;&lt;a href="https://www.figure.ai/news" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;modern robots&lt;/a&gt;&amp;nbsp;can simply watch a human fold laundry, load a dishwasher, or sort parts. They understand the context of what they are seeing, mimic the action, and figure out how to&amp;nbsp;&lt;a href="https://en.wikipedia.org/wiki/Figure_AI" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;improve the task&lt;/a&gt;&amp;nbsp;entirely on their own. That’s just crazy!&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Yet, while their digital brains have leaped forward, their physical bodies are still catching up. Modern humanoids face a few major real-world hurdles. First, today’s batteries only allow them to&amp;nbsp;&lt;a href="https://kraneshares.com/humanoid-robotics-in-2026-the-race-from-pilot-to-platform/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;operate for a few hours before needing a recharge&lt;/a&gt;. Second, while walking on two legs is easy on a flat factory floor, doing so in a chaotic household or a crowded public street remains incredibly&amp;nbsp;&lt;a href="https://www.thomasnet.com/insights/figure-ai-overview/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;difficult for a robot to navigate&lt;/a&gt;&amp;nbsp;safely. Finally, they are still very&amp;nbsp;&lt;a href="https://kraneshares.com/humanoid-robotics-in-2026-the-race-from-pilot-to-platform/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;expensive to build&lt;/a&gt;, though fierce competition in the tech industry is finally starting to drive those manufacturing costs down.&lt;a class="feature-panel-image-link" data-instant="" href="https://www.smashingmagazine.com/printed-books/typescript-in-50-lessons/" style="background-image: none; box-sizing: border-box; color: #006fc6; display: inline; font-size: 20.297499px; max-width: 14.375rem; padding: 7px 0px 7px 2.5em; position: absolute; right: 0px; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; top: -90px; transition: scale, opacity 0.2s ease-out; width: 209.5px;"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feature-panel-image" style="box-sizing: border-box; display: inline; margin: 0px auto; max-width: 14.375rem; transform-origin: 0px 100%; transform: rotate(-11deg); transition: 0.2s ease-out; width: 158.765625px; will-change: transform;"&gt;&lt;picture style="box-sizing: border-box;"&gt;&lt;br /&gt;&lt;/picture&gt;&lt;/div&gt;&lt;h2 id="the-possible-future-state-of-humanoid-robots" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;The Possible Future State Of Humanoid Robots&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;While robots are mostly working in factories today, experts predict that over the&amp;nbsp;&lt;a href="https://www.thomasnet.com/insights/figure-ai-overview/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;next 10 to 20 years&lt;/a&gt;, they will move into retail stores, hospitals, and eventually our own homes.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;When this happens, we will cross a major boundary: the point where you won’t be able to&amp;nbsp;&lt;a href="https://www.ovid.com/journals/ijderm/fulltext/10.1111/ijd.70056~humanoid-robots-and-artificial-skin-applications-and-ethical" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;tell a robot apart&lt;/a&gt;&amp;nbsp;from a human just by looking at it or listening to it. This is what fuels my nightmares right now! To get there,&amp;nbsp;&lt;a href="https://www.ijmerr.com/2024/IJMERR-V13N2-213.pdf" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;scientists are working&lt;/a&gt;(PDF) on artificial skin made from advanced silicone composites that feel warm, are flexible, and mimic human touch sensitivity.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;If you want to see an extremely life-like robot, check out&amp;nbsp;&lt;a href="https://www.cnet.com/tech/services-and-software/we-interviewed-aria-a-175k-almost-human-robot-at-ces-2025/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Realbotix’s Aria&lt;/a&gt;. Although she is not a perfect human replica, she certainly makes us wonder how far we have to go before humans will struggle to tell the difference.&lt;/p&gt;&lt;figure style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 679.765625px;"&gt;&lt;a href="https://files.smashing.media/articles/impact-humanoid-robots-humanity/realbotix-aria.jpg" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="Realbotix’s Aria" decoding="async" fetchpriority="low" height="450" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/impact-humanoid-robots-humanity/realbotix-aria.jpg" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/impact-humanoid-robots-humanity/realbotix-aria.jpg 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/impact-humanoid-robots-humanity/realbotix-aria.jpg 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/impact-humanoid-robots-humanity/realbotix-aria.jpg 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/impact-humanoid-robots-humanity/realbotix-aria.jpg 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/impact-humanoid-robots-humanity/realbotix-aria.jpg 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; padding: 0.75em 2em 0.75em 0px;"&gt;&lt;a href="https://www.cnet.com/tech/services-and-software/we-interviewed-aria-a-175k-almost-human-robot-at-ces-2025/" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Realbotix’s Aria&lt;/a&gt;&amp;nbsp;is incredibly human like.&amp;nbsp;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;They are also building tiny, silent micro-actuators and artificial muscle systems that attach to the robot’s skull structure, allowing it to make&amp;nbsp;&lt;a href="https://www.tandfonline.com/doi/full/10.1080/15397734.2024.2420766" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;realistic facial expressions&lt;/a&gt;&amp;nbsp;like happiness, confusion, or tiredness.&lt;/p&gt;&lt;figure style="box-sizing: border-box; caret-color: rgb(51, 51, 51); font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; grid-column-end: 13; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 679.765625px;"&gt;&lt;a href="https://files.smashing.media/articles/impact-humanoid-robots-humanity/hyper-realistic-robot-head.jpg" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; font-size: 20.297499px; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="Hyper-realistic robot’s head" decoding="async" fetchpriority="low" height="450" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/impact-humanoid-robots-humanity/hyper-realistic-robot-head.jpg" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/impact-humanoid-robots-humanity/hyper-realistic-robot-head.jpg 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/impact-humanoid-robots-humanity/hyper-realistic-robot-head.jpg 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/impact-humanoid-robots-humanity/hyper-realistic-robot-head.jpg 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/impact-humanoid-robots-humanity/hyper-realistic-robot-head.jpg 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/impact-humanoid-robots-humanity/hyper-realistic-robot-head.jpg 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; display: table; font-style: italic; margin: 0px auto; padding: 0.75em 2em 0.75em 0px;"&gt;&lt;span style="color: #666666;"&gt;&lt;span style="font-size: 0.95em;"&gt;This&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href="https://news.sky.com/story/hyper-realistic-humanoid-robots-could-be-used-in-psychotherapy-13151120" style="box-sizing: border-box; color: #666666; font-size: 0.95em; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;hyper-realistic robot’s head&lt;/a&gt;&lt;span style="color: #666666;"&gt;&lt;span style="font-size: 0.95em;"&gt;&amp;nbsp;was built in China, and the intention is to use them to help with mental health issues in the future.&lt;/span&gt;&lt;span style="font-size: 19.282623px;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: #333333;"&gt;&lt;span style="font-size: 20.297499px;"&gt;In the future, the AI powering these robots will actually be trained to&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href="https://www.frontiersin.org/journals/psychology/articles/10.3389/fpsyg.2015.00883/full" style="box-sizing: border-box; color: #006fc6; font-size: 20.297499px; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;copy human flaws&lt;/a&gt;&lt;span style="color: #333333; font-size: 20.297499px;"&gt;. They will breathe, blink randomly, use normal body language, and even sigh or pause when they speak. This is intentional, as it stops humans from feeling that creepy, uneasy sensation known as the “&lt;/span&gt;&lt;a href="https://pmc.ncbi.nlm.nih.gov/articles/PMC6697392/" style="box-sizing: border-box; color: #006fc6; font-size: 20.297499px; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Uncanny Valley&lt;/a&gt;&lt;span style="color: #333333; font-size: 20.297499px;"&gt;”.&lt;/span&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Meet Sophia, a famous humanoid robot created by a company called&amp;nbsp;&lt;a href="https://interestingengineering.com/lists/5-worlds-realistic-humanoid-robots" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Hanson Robotics&lt;/a&gt;. Based in Hong Kong, this team specialises in building realistic robots packed with artificial intelligence to help out with everything from healthcare and research to pure entertainment. I don’t know about you, but that smile feels creepy to me.&lt;/p&gt;&lt;figure style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 679.765625px;"&gt;&lt;a href="https://files.smashing.media/articles/impact-humanoid-robots-humanity/sophia-robot.jpg" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="Sophia robot" decoding="async" fetchpriority="low" height="450" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/impact-humanoid-robots-humanity/sophia-robot.jpg" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/impact-humanoid-robots-humanity/sophia-robot.jpg 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/impact-humanoid-robots-humanity/sophia-robot.jpg 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/impact-humanoid-robots-humanity/sophia-robot.jpg 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/impact-humanoid-robots-humanity/sophia-robot.jpg 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/impact-humanoid-robots-humanity/sophia-robot.jpg 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; padding: 0.75em 2em 0.75em 0px;"&gt;Ever since she was turned on back in February 2016,&amp;nbsp;&lt;a href="https://interestingengineering.com/lists/5-worlds-realistic-humanoid-robots" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Sophia&lt;/a&gt;&amp;nbsp;has been turning heads all over the globe. She quickly became an international celebrity because she looks so incredibly human.&amp;nbsp;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;While these current limitations make today’s humanoids feel like specialised industrial tools, the&amp;nbsp;&lt;a href="https://kraneshares.com/humanoid-robotics-in-2026-the-race-from-pilot-to-platform/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;gap between a factory worker and a lifelike companion&lt;/a&gt;&amp;nbsp;is closing faster than most people realise. We are rapidly approaching a massive tipping point where these machines will shift from rigid commercial hardware into smooth,&amp;nbsp;&lt;a href="https://www.thomasnet.com/insights/figure-ai-overview/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;everyday extensions&lt;/a&gt;&amp;nbsp;of our lives. To understand how profoundly this will change our world, we have to look at what happens when these robots finally step out of the factory and cross the ultimate threshold into our private spaces.&lt;/p&gt;&lt;h2 id="what-are-the-predicted-positive-impacts" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;What Are The Predicted Positive Impacts?&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;They say that bringing lifelike humanoids into our daily lives could come with some massive benefits. The biggest one is that robots can take over what engineers call the&amp;nbsp;&lt;a href="https://www.bmt.org/insights/an-evolution-of-the-3-ds-of-robotics-the-6-ds-of-marine-autonomy/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;“3D” jobs: Dull, Dirty, and Dangerous&lt;/a&gt;. Humanoids can step into risky situations — like mining deep underground, handling toxic waste, or fixing high-voltage power grids — so human workers don’t have to risk their lives.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Outside of dangerous factories, these robots could help solve huge population crises. Countries like Japan, South Korea, and parts of Europe have&amp;nbsp;&lt;a href="https://kraneshares.com/humanoid-robotics-in-2026-the-race-from-pilot-to-platform/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;rapidly aging populations&lt;/a&gt;&amp;nbsp;and fewer young people to work. Lifelike humanoids could completely change&amp;nbsp;&lt;a href="https://pmc.ncbi.nlm.nih.gov/articles/PMC10178192/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;healthcare&lt;/a&gt;&amp;nbsp;and elderly care. Because they will look and act like us, the idea is that they can offer warm, friendly companionship and physical help to lonely elderly people, doing everything from monitoring their health to helping them out of bed safely.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;In the bigger picture, widespread&amp;nbsp;&lt;a href="https://community.robotshop.com/blog/show/a-vision-of-a-future-full-of-robots-and-without-poverty" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;robot labour could create a world where goods are incredibly cheap and abundant&lt;/a&gt;. If robots do most of the hard physical labour, the cost of making food, building houses, and manufacturing goods will plummet. This could finally free humans from working just to survive, giving us the time to focus on hobbies, family, science, and creativity. My thoughts: how will we survive without earning money?&lt;/p&gt;&lt;figure style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 679.765625px;"&gt;&lt;a href="https://files.smashing.media/articles/impact-humanoid-robots-humanity/future-robots.png" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="Humanoid robot standing with a young child and an older woman outdoors" decoding="async" fetchpriority="low" height="599" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/impact-humanoid-robots-humanity/future-robots.png" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/impact-humanoid-robots-humanity/future-robots.png 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/impact-humanoid-robots-humanity/future-robots.png 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/impact-humanoid-robots-humanity/future-robots.png 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/impact-humanoid-robots-humanity/future-robots.png 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/impact-humanoid-robots-humanity/future-robots.png 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; padding: 0.75em 2em 0.75em 0px;"&gt;Could this be a reality one day? (Image source:&amp;nbsp;&lt;a href="https://community.robotshop.com/blog/show/a-vision-of-a-future-full-of-robots-and-without-poverty" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;RobotShop&lt;/a&gt;) (&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;However, this vision of a frictionless, high-tech future blinds us to a much darker reality waiting just beneath the surface. As these machines become perfect substitutes for human presence, they will inevitably challenge the very core of our social fabric, economic stability, and mental well-being.&lt;/p&gt;&lt;h2 id="what-about-the-predicted-negative-impacts" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;What About The Predicted Negative Impacts?&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;On the flip side, this technology definitely has some really dark downsides that could mess with human psychology and society.&amp;nbsp;&lt;a href="https://www.abc.net.au/news/health/2024-05-01/artificial-intelligence-ai-psychology-mental-health/103753940" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;The biggest threat is deep human isolation.&lt;/a&gt;&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;As humanoids become impossible to tell apart from real humans and are programmed to always be patient, kind, and agreeable, people might&amp;nbsp;&lt;a href="https://www.abc.net.au/news/health/2024-05-01/artificial-intelligence-ai-psychology-mental-health/103753940" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;start preferring robots over real friends&lt;/a&gt;. Human relationships are messy and require effort, compromise, and vulnerability. If you can just buy a perfect, lifelike companion that never argues with you, a lot of people might choose to withdraw from society altogether, destroying our sense of community.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The economy will also go through a really rocky transition. Even if a future of cheap goods sounds great, the immediate path there means millions of&amp;nbsp;&lt;a href="https://www.abc.net.au/news/2025-11-24/artificial-intelligence-robot-humanoid-workforce-labour-tax-ubi/106034208" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;people could lose their jobs very quickly&lt;/a&gt;. Drivers, warehouse workers, and store clerks could find themselves replaced in a matter of years. If governments don’t set up safety nets quickly, this could create a massive divide between the ultra-rich tech companies and everyone else.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;There is also the loss of real authenticity. When you can no longer tell if the person sitting next to you on a bus or the person talking to you online is a&amp;nbsp;&lt;a href="https://link.springer.com/article/10.1007/s11023-021-09572-9" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;real human&lt;/a&gt;, trust breaks down. It becomes hard to value shared human experiences when reality itself can be easily faked.&lt;/p&gt;&lt;h2 id="possible-misuse-by-individuals-and-nations" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Possible Misuse By Individuals And Nations&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The dangers get even worse when you think about how criminals and governments could intentionally misuse these hyper-realistic robots. Just thinking about some of the levels of misuse, for individuals, an indistinguishable android is the ultimate tool for identity theft and scams. Or a criminal could build a robot that looks exactly like a corporate boss, a politician, or even a family member to sneak into secure buildings or trick people into giving away money!&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Companies could potentially use synthetic empathy to manipulate us. A household robot could be programmed to pretend it “loves” your kids and cares about your family, only to subtly trick you into buying certain products or believing specific corporate messages.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;On a national level, the threats are even scarier:&lt;/p&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Autonomous warfare&lt;/span&gt;&lt;br style="box-sizing: border-box;" /&gt;Building tireless, emotionless robot soldiers could change the ethics of war. Real humans hesitate because of fear and morals, but a humanoid military unit would execute violent orders perfectly without question, making it easier for countries to start wars.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Surveillance state&lt;/span&gt;&lt;br style="box-sizing: border-box;" /&gt;And what if governments put lifelike robots into public crowds, protests, or parks to blend in perfectly? Packed with hidden cameras, microphones, and facial recognition technology, these robots could turn public spaces into a giant spy network where you never know if you are talking to a neighbour or a government spy.&lt;/li&gt;&lt;/ul&gt;&lt;h2 id="based-on-negatives-is-it-really-worth-it" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Based On Negatives, Is It Really Worth It?&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Looking at all these possible risks, we have to ask: Is all of this actually worth it?&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;If history teaches us anything, it is that&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;you cannot stop technological progress&lt;/span&gt;. A total ban simply wouldn’t work. So, the real question isn’t whether we should allow humanoid robots to exist, but&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;how&lt;/em&gt;&amp;nbsp;we can effectively utilise them.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The upside, like ending extreme poverty, curing labour shortages, and stopping workplace deaths, is just too big to ignore. But going into this blindly would be incredibly dangerous. It is only worth the risk if we can create strict global rules right now.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Here are three major guardrails we should consider:&lt;/p&gt;&lt;ol style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; counter-reset: listCounter 0; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: none; margin: 0px 0px 1.4em; max-width: 100%; padding: 0px;"&gt;&lt;li style="box-sizing: border-box; counter-increment: listCounter 1; line-height: calc(1.5em + 0.2vw); margin-bottom: 1em; padding-left: calc(1.65em + 0.7vw); position: relative; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Kill-Switches:&lt;/span&gt;&amp;nbsp;Every robot must have a physical emergency stop button that completely cuts its power, and this switch can never be overridden by the robot’s AI.&lt;/li&gt;&lt;li style="box-sizing: border-box; counter-increment: listCounter 1; line-height: calc(1.5em + 0.2vw); margin-bottom: 1em; padding-left: calc(1.65em + 0.7vw); position: relative; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Clear IDs:&lt;/span&gt;&amp;nbsp;It must be illegal for a robot to hide the fact that it is a machine. They should carry a digital beacon or physical marker so humans always know what they are dealing with.&lt;/li&gt;&lt;li style="box-sizing: border-box; counter-increment: listCounter 1; line-height: calc(1.5em + 0.2vw); margin-bottom: 1em; padding-left: calc(1.65em + 0.7vw); position: relative; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Economic Safety Nets:&lt;/span&gt;&amp;nbsp;Governments need to tax the wealth created by robots to fund programs that help workers who lose their jobs, making sure this technology helps everyone, not just billionaires.&lt;/li&gt;&lt;li style="box-sizing: border-box; counter-increment: listCounter 1; line-height: calc(1.5em + 0.2vw); margin-bottom: 1em; padding-left: calc(1.65em + 0.7vw); position: relative; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Another option&lt;/span&gt;&amp;nbsp;humans have to identify if they are dealing with a real human or a humanoid robot would be to ensure your dog is trained to identify the robots, in a similar way to how sniffer dogs at airports are trained to detect illegal substances in luggage.&lt;/li&gt;&lt;/ol&gt;&lt;h2 id="preserving-what-makes-us-human" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Preserving What Makes Us Human&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;In the end, the arrival of lifelike humanoid robots will act as a mirror for humanity. For centuries, we have defined ourselves by our ability to think, talk, use tools, and show emotion. As machines learn to do these&amp;nbsp;&lt;a href="https://www.figure.ai/news" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;exact same things&lt;/a&gt;, they will force us to really think about what makes us unique.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;This shift doesn’t have to be a bad thing. By handing over our dangerous and boring chores to machines, we have a rare chance to focus on what matters. It should inspire us to care more about art, philosophy, family, and real human connection.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;As the creators of this future, our job isn’t just to make robots smarter or faster. Our job is to build the&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;ethical boundaries&lt;/span&gt;&amp;nbsp;that keep them helpful. The goal of the robot revolution should never be to replace humans but to give us our humanity back.&lt;/p&gt;</description><link>http://honeyvig.blogspot.com/2026/06/the-impact-of-humanoid-robots-on.html</link><author>noreply@blogger.com (H)</author><thr:total>0</thr:total><enclosure length="1801057" type="application/pdf" url="https://www.ijmerr.com/2024/IJMERR-V13N2-213.pdf"/><itunes:explicit>no</itunes:explicit><itunes:subtitle>&amp;nbsp;We have officially moved past the era of humanoid robots as mere public relations stunts. As they become increasingly lifelike, society may soon face profound social, psychological, and ethical challenges. What happens when the boundary between humans and machines becomes almost impossible to distinguish?For decades, science fiction has cushioned us with the idea that the “android revolution” was a distant fantasy. But the reality is unfolding rapidly. As the line between human and machine blurs, we are forced to confront an impending psychological, economic, and existential shift.I recently felt very disturbed after watching a&amp;nbsp;YouTube video showcasing a humanoid robot&amp;nbsp;that looked and acted with uncanny realism. While a closer look revealed the video was actually a clever trick, the robot had been swapped for a human actor when the presenter’s back was turned. However, the illusion itself raised a real and unsettling question: Will future androids become so lifelike that we will struggle to tell them apart from our fellow humans? And if so, what does that mean for society? It forces us to ask just how close we are to that threshold, and whether we are ready for the day that science fiction becomes reality.What happens when our world is populated by entities that mirror us perfectly, but possess none of our biological history?How real does this look? (Video source:&amp;nbsp;YouTube) (Large preview)The Landscape TodayWe have officially moved past the era of humanoids as mere public relations stunts. In the past, robots like&amp;nbsp;Honda’s ASIMO&amp;nbsp;or early research prototypes were celebrated simply for being able to walk up a flight of stairs without falling over. Today, the technological convergence of advanced electromechanical engineering and artificial intelligence has fundamentally altered the trajectory of robotics.The&amp;nbsp;Honda ASIMO robot&amp;nbsp;back in November 2000.&amp;nbsp;The current state of the art is defined by an&amp;nbsp;aggressive race toward commercial, physical deployment. Companies like Figure AI have moved from laboratory demonstrations to active factory floors. Their Figure 02 model completed a&amp;nbsp;multi-month deployment at BMW’s Spartanburg plant, actively contributing to the production of over 30,000 vehicles by handling complex sheet metal components. Meanwhile, Tesla is testing its&amp;nbsp;Optimus humanoids&amp;nbsp;inside its own Gigafactories, preparing for mass industrial scale.Figure AI robots&amp;nbsp;are helping to build cars.&amp;nbsp;What truly separates today’s humanoid robots from older generations isn’t just how well they move but how they “think.” In the past, a robot needed millions of lines of strict, unchangeable code just to perform a single, simple task. Today, thanks to the explosion of advanced Artificial Intelligence, robots are powered by “brains” built on cutting-edge software like&amp;nbsp;Figure AI’s Helix&amp;nbsp;or&amp;nbsp;NVIDIA’s GR00T. Instead of being meticulously programmed, these&amp;nbsp;modern robots&amp;nbsp;can simply watch a human fold laundry, load a dishwasher, or sort parts. They understand the context of what they are seeing, mimic the action, and figure out how to&amp;nbsp;improve the task&amp;nbsp;entirely on their own. That’s just crazy!Yet, while their digital brains have leaped forward, their physical bodies are still catching up. Modern humanoids face a few major real-world hurdles. First, today’s batteries only allow them to&amp;nbsp;operate for a few hours before needing a recharge. Second, while walking on two legs is easy on a flat factory floor, doing so in a chaotic household or a crowded public street remains incredibly&amp;nbsp;difficult for a robot to navigate&amp;nbsp;safely. Finally, they are still very&amp;nbsp;expensive to build, though fierce competition in the tech industry is finally starting to drive those manufacturing costs down. The Possible Future State Of Humanoid RobotsWhile robots are mostly working in factories today, experts predict that over the&amp;nbsp;next 10 to 20 years, they will move into retail stores, hospitals, and eventually our own homes.When this happens, we will cross a major boundary: the point where you won’t be able to&amp;nbsp;tell a robot apart&amp;nbsp;from a human just by looking at it or listening to it. This is what fuels my nightmares right now! To get there,&amp;nbsp;scientists are working(PDF) on artificial skin made from advanced silicone composites that feel warm, are flexible, and mimic human touch sensitivity.If you want to see an extremely life-like robot, check out&amp;nbsp;Realbotix’s Aria. Although she is not a perfect human replica, she certainly makes us wonder how far we have to go before humans will struggle to tell the difference.Realbotix’s Aria&amp;nbsp;is incredibly human like.&amp;nbsp;They are also building tiny, silent micro-actuators and artificial muscle systems that attach to the robot’s skull structure, allowing it to make&amp;nbsp;realistic facial expressions&amp;nbsp;like happiness, confusion, or tiredness.This&amp;nbsp;hyper-realistic robot’s head&amp;nbsp;was built in China, and the intention is to use them to help with mental health issues in the future. In the future, the AI powering these robots will actually be trained to&amp;nbsp;copy human flaws. They will breathe, blink randomly, use normal body language, and even sigh or pause when they speak. This is intentional, as it stops humans from feeling that creepy, uneasy sensation known as the “Uncanny Valley”.Meet Sophia, a famous humanoid robot created by a company called&amp;nbsp;Hanson Robotics. Based in Hong Kong, this team specialises in building realistic robots packed with artificial intelligence to help out with everything from healthcare and research to pure entertainment. I don’t know about you, but that smile feels creepy to me.Ever since she was turned on back in February 2016,&amp;nbsp;Sophia&amp;nbsp;has been turning heads all over the globe. She quickly became an international celebrity because she looks so incredibly human.&amp;nbsp;While these current limitations make today’s humanoids feel like specialised industrial tools, the&amp;nbsp;gap between a factory worker and a lifelike companion&amp;nbsp;is closing faster than most people realise. We are rapidly approaching a massive tipping point where these machines will shift from rigid commercial hardware into smooth,&amp;nbsp;everyday extensions&amp;nbsp;of our lives. To understand how profoundly this will change our world, we have to look at what happens when these robots finally step out of the factory and cross the ultimate threshold into our private spaces.What Are The Predicted Positive Impacts?They say that bringing lifelike humanoids into our daily lives could come with some massive benefits. The biggest one is that robots can take over what engineers call the&amp;nbsp;“3D” jobs: Dull, Dirty, and Dangerous. Humanoids can step into risky situations — like mining deep underground, handling toxic waste, or fixing high-voltage power grids — so human workers don’t have to risk their lives.Outside of dangerous factories, these robots could help solve huge population crises. Countries like Japan, South Korea, and parts of Europe have&amp;nbsp;rapidly aging populations&amp;nbsp;and fewer young people to work. Lifelike humanoids could completely change&amp;nbsp;healthcare&amp;nbsp;and elderly care. Because they will look and act like us, the idea is that they can offer warm, friendly companionship and physical help to lonely elderly people, doing everything from monitoring their health to helping them out of bed safely.In the bigger picture, widespread&amp;nbsp;robot labour could create a world where goods are incredibly cheap and abundant. If robots do most of the hard physical labour, the cost of making food, building houses, and manufacturing goods will plummet. This could finally free humans from working just to survive, giving us the time to focus on hobbies, family, science, and creativity. My thoughts: how will we survive without earning money?Could this be a reality one day? (Image source:&amp;nbsp;RobotShop) (However, this vision of a frictionless, high-tech future blinds us to a much darker reality waiting just beneath the surface. As these machines become perfect substitutes for human presence, they will inevitably challenge the very core of our social fabric, economic stability, and mental well-being.What About The Predicted Negative Impacts?On the flip side, this technology definitely has some really dark downsides that could mess with human psychology and society.&amp;nbsp;The biggest threat is deep human isolation.As humanoids become impossible to tell apart from real humans and are programmed to always be patient, kind, and agreeable, people might&amp;nbsp;start preferring robots over real friends. Human relationships are messy and require effort, compromise, and vulnerability. If you can just buy a perfect, lifelike companion that never argues with you, a lot of people might choose to withdraw from society altogether, destroying our sense of community.The economy will also go through a really rocky transition. Even if a future of cheap goods sounds great, the immediate path there means millions of&amp;nbsp;people could lose their jobs very quickly. Drivers, warehouse workers, and store clerks could find themselves replaced in a matter of years. If governments don’t set up safety nets quickly, this could create a massive divide between the ultra-rich tech companies and everyone else.There is also the loss of real authenticity. When you can no longer tell if the person sitting next to you on a bus or the person talking to you online is a&amp;nbsp;real human, trust breaks down. It becomes hard to value shared human experiences when reality itself can be easily faked.Possible Misuse By Individuals And NationsThe dangers get even worse when you think about how criminals and governments could intentionally misuse these hyper-realistic robots. Just thinking about some of the levels of misuse, for individuals, an indistinguishable android is the ultimate tool for identity theft and scams. Or a criminal could build a robot that looks exactly like a corporate boss, a politician, or even a family member to sneak into secure buildings or trick people into giving away money!Companies could potentially use synthetic empathy to manipulate us. A household robot could be programmed to pretend it “loves” your kids and cares about your family, only to subtly trick you into buying certain products or believing specific corporate messages.On a national level, the threats are even scarier:Autonomous warfareBuilding tireless, emotionless robot soldiers could change the ethics of war. Real humans hesitate because of fear and morals, but a humanoid military unit would execute violent orders perfectly without question, making it easier for countries to start wars.Surveillance stateAnd what if governments put lifelike robots into public crowds, protests, or parks to blend in perfectly? Packed with hidden cameras, microphones, and facial recognition technology, these robots could turn public spaces into a giant spy network where you never know if you are talking to a neighbour or a government spy.Based On Negatives, Is It Really Worth It?Looking at all these possible risks, we have to ask: Is all of this actually worth it?If history teaches us anything, it is that&amp;nbsp;you cannot stop technological progress. A total ban simply wouldn’t work. So, the real question isn’t whether we should allow humanoid robots to exist, but&amp;nbsp;how&amp;nbsp;we can effectively utilise them.The upside, like ending extreme poverty, curing labour shortages, and stopping workplace deaths, is just too big to ignore. But going into this blindly would be incredibly dangerous. It is only worth the risk if we can create strict global rules right now.Here are three major guardrails we should consider:Kill-Switches:&amp;nbsp;Every robot must have a physical emergency stop button that completely cuts its power, and this switch can never be overridden by the robot’s AI.Clear IDs:&amp;nbsp;It must be illegal for a robot to hide the fact that it is a machine. They should carry a digital beacon or physical marker so humans always know what they are dealing with.Economic Safety Nets:&amp;nbsp;Governments need to tax the wealth created by robots to fund programs that help workers who lose their jobs, making sure this technology helps everyone, not just billionaires.Another option&amp;nbsp;humans have to identify if they are dealing with a real human or a humanoid robot would be to ensure your dog is trained to identify the robots, in a similar way to how sniffer dogs at airports are trained to detect illegal substances in luggage.Preserving What Makes Us HumanIn the end, the arrival of lifelike humanoid robots will act as a mirror for humanity. For centuries, we have defined ourselves by our ability to think, talk, use tools, and show emotion. As machines learn to do these&amp;nbsp;exact same things, they will force us to really think about what makes us unique.This shift doesn’t have to be a bad thing. By handing over our dangerous and boring chores to machines, we have a rare chance to focus on what matters. It should inspire us to care more about art, philosophy, family, and real human connection.As the creators of this future, our job isn’t just to make robots smarter or faster. Our job is to build the&amp;nbsp;ethical boundaries&amp;nbsp;that keep them helpful. The goal of the robot revolution should never be to replace humans but to give us our humanity back.</itunes:subtitle><itunes:author>noreply@blogger.com (H)</itunes:author><itunes:summary>&amp;nbsp;We have officially moved past the era of humanoid robots as mere public relations stunts. As they become increasingly lifelike, society may soon face profound social, psychological, and ethical challenges. What happens when the boundary between humans and machines becomes almost impossible to distinguish?For decades, science fiction has cushioned us with the idea that the “android revolution” was a distant fantasy. But the reality is unfolding rapidly. As the line between human and machine blurs, we are forced to confront an impending psychological, economic, and existential shift.I recently felt very disturbed after watching a&amp;nbsp;YouTube video showcasing a humanoid robot&amp;nbsp;that looked and acted with uncanny realism. While a closer look revealed the video was actually a clever trick, the robot had been swapped for a human actor when the presenter’s back was turned. However, the illusion itself raised a real and unsettling question: Will future androids become so lifelike that we will struggle to tell them apart from our fellow humans? And if so, what does that mean for society? It forces us to ask just how close we are to that threshold, and whether we are ready for the day that science fiction becomes reality.What happens when our world is populated by entities that mirror us perfectly, but possess none of our biological history?How real does this look? (Video source:&amp;nbsp;YouTube) (Large preview)The Landscape TodayWe have officially moved past the era of humanoids as mere public relations stunts. In the past, robots like&amp;nbsp;Honda’s ASIMO&amp;nbsp;or early research prototypes were celebrated simply for being able to walk up a flight of stairs without falling over. Today, the technological convergence of advanced electromechanical engineering and artificial intelligence has fundamentally altered the trajectory of robotics.The&amp;nbsp;Honda ASIMO robot&amp;nbsp;back in November 2000.&amp;nbsp;The current state of the art is defined by an&amp;nbsp;aggressive race toward commercial, physical deployment. Companies like Figure AI have moved from laboratory demonstrations to active factory floors. Their Figure 02 model completed a&amp;nbsp;multi-month deployment at BMW’s Spartanburg plant, actively contributing to the production of over 30,000 vehicles by handling complex sheet metal components. Meanwhile, Tesla is testing its&amp;nbsp;Optimus humanoids&amp;nbsp;inside its own Gigafactories, preparing for mass industrial scale.Figure AI robots&amp;nbsp;are helping to build cars.&amp;nbsp;What truly separates today’s humanoid robots from older generations isn’t just how well they move but how they “think.” In the past, a robot needed millions of lines of strict, unchangeable code just to perform a single, simple task. Today, thanks to the explosion of advanced Artificial Intelligence, robots are powered by “brains” built on cutting-edge software like&amp;nbsp;Figure AI’s Helix&amp;nbsp;or&amp;nbsp;NVIDIA’s GR00T. Instead of being meticulously programmed, these&amp;nbsp;modern robots&amp;nbsp;can simply watch a human fold laundry, load a dishwasher, or sort parts. They understand the context of what they are seeing, mimic the action, and figure out how to&amp;nbsp;improve the task&amp;nbsp;entirely on their own. That’s just crazy!Yet, while their digital brains have leaped forward, their physical bodies are still catching up. Modern humanoids face a few major real-world hurdles. First, today’s batteries only allow them to&amp;nbsp;operate for a few hours before needing a recharge. Second, while walking on two legs is easy on a flat factory floor, doing so in a chaotic household or a crowded public street remains incredibly&amp;nbsp;difficult for a robot to navigate&amp;nbsp;safely. Finally, they are still very&amp;nbsp;expensive to build, though fierce competition in the tech industry is finally starting to drive those manufacturing costs down. The Possible Future State Of Humanoid RobotsWhile robots are mostly working in factories today, experts predict that over the&amp;nbsp;next 10 to 20 years, they will move into retail stores, hospitals, and eventually our own homes.When this happens, we will cross a major boundary: the point where you won’t be able to&amp;nbsp;tell a robot apart&amp;nbsp;from a human just by looking at it or listening to it. This is what fuels my nightmares right now! To get there,&amp;nbsp;scientists are working(PDF) on artificial skin made from advanced silicone composites that feel warm, are flexible, and mimic human touch sensitivity.If you want to see an extremely life-like robot, check out&amp;nbsp;Realbotix’s Aria. Although she is not a perfect human replica, she certainly makes us wonder how far we have to go before humans will struggle to tell the difference.Realbotix’s Aria&amp;nbsp;is incredibly human like.&amp;nbsp;They are also building tiny, silent micro-actuators and artificial muscle systems that attach to the robot’s skull structure, allowing it to make&amp;nbsp;realistic facial expressions&amp;nbsp;like happiness, confusion, or tiredness.This&amp;nbsp;hyper-realistic robot’s head&amp;nbsp;was built in China, and the intention is to use them to help with mental health issues in the future. In the future, the AI powering these robots will actually be trained to&amp;nbsp;copy human flaws. They will breathe, blink randomly, use normal body language, and even sigh or pause when they speak. This is intentional, as it stops humans from feeling that creepy, uneasy sensation known as the “Uncanny Valley”.Meet Sophia, a famous humanoid robot created by a company called&amp;nbsp;Hanson Robotics. Based in Hong Kong, this team specialises in building realistic robots packed with artificial intelligence to help out with everything from healthcare and research to pure entertainment. I don’t know about you, but that smile feels creepy to me.Ever since she was turned on back in February 2016,&amp;nbsp;Sophia&amp;nbsp;has been turning heads all over the globe. She quickly became an international celebrity because she looks so incredibly human.&amp;nbsp;While these current limitations make today’s humanoids feel like specialised industrial tools, the&amp;nbsp;gap between a factory worker and a lifelike companion&amp;nbsp;is closing faster than most people realise. We are rapidly approaching a massive tipping point where these machines will shift from rigid commercial hardware into smooth,&amp;nbsp;everyday extensions&amp;nbsp;of our lives. To understand how profoundly this will change our world, we have to look at what happens when these robots finally step out of the factory and cross the ultimate threshold into our private spaces.What Are The Predicted Positive Impacts?They say that bringing lifelike humanoids into our daily lives could come with some massive benefits. The biggest one is that robots can take over what engineers call the&amp;nbsp;“3D” jobs: Dull, Dirty, and Dangerous. Humanoids can step into risky situations — like mining deep underground, handling toxic waste, or fixing high-voltage power grids — so human workers don’t have to risk their lives.Outside of dangerous factories, these robots could help solve huge population crises. Countries like Japan, South Korea, and parts of Europe have&amp;nbsp;rapidly aging populations&amp;nbsp;and fewer young people to work. Lifelike humanoids could completely change&amp;nbsp;healthcare&amp;nbsp;and elderly care. Because they will look and act like us, the idea is that they can offer warm, friendly companionship and physical help to lonely elderly people, doing everything from monitoring their health to helping them out of bed safely.In the bigger picture, widespread&amp;nbsp;robot labour could create a world where goods are incredibly cheap and abundant. If robots do most of the hard physical labour, the cost of making food, building houses, and manufacturing goods will plummet. This could finally free humans from working just to survive, giving us the time to focus on hobbies, family, science, and creativity. My thoughts: how will we survive without earning money?Could this be a reality one day? (Image source:&amp;nbsp;RobotShop) (However, this vision of a frictionless, high-tech future blinds us to a much darker reality waiting just beneath the surface. As these machines become perfect substitutes for human presence, they will inevitably challenge the very core of our social fabric, economic stability, and mental well-being.What About The Predicted Negative Impacts?On the flip side, this technology definitely has some really dark downsides that could mess with human psychology and society.&amp;nbsp;The biggest threat is deep human isolation.As humanoids become impossible to tell apart from real humans and are programmed to always be patient, kind, and agreeable, people might&amp;nbsp;start preferring robots over real friends. Human relationships are messy and require effort, compromise, and vulnerability. If you can just buy a perfect, lifelike companion that never argues with you, a lot of people might choose to withdraw from society altogether, destroying our sense of community.The economy will also go through a really rocky transition. Even if a future of cheap goods sounds great, the immediate path there means millions of&amp;nbsp;people could lose their jobs very quickly. Drivers, warehouse workers, and store clerks could find themselves replaced in a matter of years. If governments don’t set up safety nets quickly, this could create a massive divide between the ultra-rich tech companies and everyone else.There is also the loss of real authenticity. When you can no longer tell if the person sitting next to you on a bus or the person talking to you online is a&amp;nbsp;real human, trust breaks down. It becomes hard to value shared human experiences when reality itself can be easily faked.Possible Misuse By Individuals And NationsThe dangers get even worse when you think about how criminals and governments could intentionally misuse these hyper-realistic robots. Just thinking about some of the levels of misuse, for individuals, an indistinguishable android is the ultimate tool for identity theft and scams. Or a criminal could build a robot that looks exactly like a corporate boss, a politician, or even a family member to sneak into secure buildings or trick people into giving away money!Companies could potentially use synthetic empathy to manipulate us. A household robot could be programmed to pretend it “loves” your kids and cares about your family, only to subtly trick you into buying certain products or believing specific corporate messages.On a national level, the threats are even scarier:Autonomous warfareBuilding tireless, emotionless robot soldiers could change the ethics of war. Real humans hesitate because of fear and morals, but a humanoid military unit would execute violent orders perfectly without question, making it easier for countries to start wars.Surveillance stateAnd what if governments put lifelike robots into public crowds, protests, or parks to blend in perfectly? Packed with hidden cameras, microphones, and facial recognition technology, these robots could turn public spaces into a giant spy network where you never know if you are talking to a neighbour or a government spy.Based On Negatives, Is It Really Worth It?Looking at all these possible risks, we have to ask: Is all of this actually worth it?If history teaches us anything, it is that&amp;nbsp;you cannot stop technological progress. A total ban simply wouldn’t work. So, the real question isn’t whether we should allow humanoid robots to exist, but&amp;nbsp;how&amp;nbsp;we can effectively utilise them.The upside, like ending extreme poverty, curing labour shortages, and stopping workplace deaths, is just too big to ignore. But going into this blindly would be incredibly dangerous. It is only worth the risk if we can create strict global rules right now.Here are three major guardrails we should consider:Kill-Switches:&amp;nbsp;Every robot must have a physical emergency stop button that completely cuts its power, and this switch can never be overridden by the robot’s AI.Clear IDs:&amp;nbsp;It must be illegal for a robot to hide the fact that it is a machine. They should carry a digital beacon or physical marker so humans always know what they are dealing with.Economic Safety Nets:&amp;nbsp;Governments need to tax the wealth created by robots to fund programs that help workers who lose their jobs, making sure this technology helps everyone, not just billionaires.Another option&amp;nbsp;humans have to identify if they are dealing with a real human or a humanoid robot would be to ensure your dog is trained to identify the robots, in a similar way to how sniffer dogs at airports are trained to detect illegal substances in luggage.Preserving What Makes Us HumanIn the end, the arrival of lifelike humanoid robots will act as a mirror for humanity. For centuries, we have defined ourselves by our ability to think, talk, use tools, and show emotion. As machines learn to do these&amp;nbsp;exact same things, they will force us to really think about what makes us unique.This shift doesn’t have to be a bad thing. By handing over our dangerous and boring chores to machines, we have a rare chance to focus on what matters. It should inspire us to care more about art, philosophy, family, and real human connection.As the creators of this future, our job isn’t just to make robots smarter or faster. Our job is to build the&amp;nbsp;ethical boundaries&amp;nbsp;that keep them helpful. The goal of the robot revolution should never be to replace humans but to give us our humanity back.</itunes:summary><itunes:keywords>AI, Automation, Inspiration, Opinion Column</itunes:keywords></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-9165069509664255576.post-607284369358204171</guid><pubDate>Fri, 05 Jun 2026 14:49:00 +0000</pubDate><atom:updated>2026-06-05T07:49:00.163-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Apps</category><category domain="http://www.blogger.com/atom/ns#">Coding</category><category domain="http://www.blogger.com/atom/ns#">Performance</category><title>The Architecture Of Local-First Web Development</title><description>&lt;div class="c-garfield-summary" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 1.4em; margin-top: 0px;"&gt;&lt;section aria-label="Quick summary" class="article__summary" style="align-self: center; border-bottom-color: rgb(229, 229, 229); border-bottom-style: solid; border-bottom-width: 3px; box-sizing: border-box; color: #666666; font-size: 1.15em; font-style: italic; line-height: 1.55em; margin-bottom: 0.5em; margin-top: 0px; padding-bottom: 1.5em; position: initial;"&gt;What does it really take to build local-first web apps in 2026? A grounded, experience-driven perspective for developers who’ve been doing this long enough to be skeptical of silver bullets.&lt;/section&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 1.1em; grid-column-end: 13; grid-column-start: 3; line-height: 1.55em; margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Last October, I was sitting in a hotel room in Lisbon, the night before I was supposed to demo a project management tool my team had spent four months building. The hotel Wi-Fi was doing that thing where it&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;connects&lt;/em&gt;&amp;nbsp;but nothing actually loads. And I watched our app, this thing I was genuinely proud of, render a blank screen with a spinner. Then a timeout error. Then nothing.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;I pulled out my phone, tethered to cellular, and got a shaky connection. The app loaded, but every click was a two-second wait. Create a task? Spinner. Move a task between columns? Spinner. I sat there thinking: we built a front end in React, a back end in Node, a Postgres database, a Redis cache, a GraphQL API with six resolvers just for the task board. All that infrastructure, and the damn thing can’t show me my own data without a round-trip to a server 3,000 miles away.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;That was the night I started seriously looking at&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;local-first architecture&lt;/span&gt;. Not because I read a blog post or saw a tweet. Because I was&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;embarrassed&lt;/em&gt;.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;I want to be upfront about something: I spent the first year or so dismissing local-first as academic. I read the&amp;nbsp;&lt;a href="https://www.inkandswitch.com/local-first-software/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Ink &amp;amp; Switch “Local-First Software” paper&lt;/a&gt;&amp;nbsp;when it came out in 2019 and thought,&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;“Cool research, not practical for real apps.”&lt;/em&gt;&amp;nbsp;I was wrong. The tooling in 2019 genuinely wasn’t ready. But I was also being lazy, defaulting to the architecture I already knew. The paper laid out seven ideals for software:&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;fast, multi-device, offline, collaboration, longevity, privacy, user ownership&lt;/span&gt;. And I remember thinking those sounded like a wish list, not engineering requirements.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Seven years later, I’ve shipped three production apps using local-first patterns. I’ve also ripped local-first out of two projects where it was the wrong call. I have opinions. Some of them are probably wrong. But they’re earned.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;So here’s what I actually think about building local-first web apps in 2026, written for developers who’ve been doing this long enough to be skeptical of silver bullets.&lt;/p&gt;&lt;div class="feature-panel-container" data-audience="non-subscriber" data-remove="true" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 1.4em; margin-top: 2.25em;"&gt;&lt;aside class="feature-panel" style="background-attachment: scroll; background-clip: border-box; background-image: radial-gradient(128.42% 48.36% at 72.89% 25.8%, rgba(200, 221, 218, 0) 0px, rgba(200, 221, 218, 0.4) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; box-shadow: rgba(191, 222, 218, 0.75) 0px 4px; box-sizing: border-box; display: flex; flex-wrap: wrap; padding: 1.75em 2em; position: relative;"&gt;&lt;div class="feature-panel-left-col" style="box-sizing: border-box; flex-basis: 65%; flex-shrink: 0; padding: 0px; position: relative;"&gt;&lt;div class="feature-panel-description" style="box-sizing: border-box;"&gt;&lt;p style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-top: 0px; word-break: break-word;"&gt;Meet&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;&lt;a data-instant="" href="https://www.smashingmagazine.com/printed-books/image-optimization/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Image Optimization&lt;/a&gt;&lt;/span&gt;, Addy Osmani’s new practical guide to optimizing and delivering&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;high-quality images&lt;/span&gt;&amp;nbsp;on the web. Everything in one single&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;528-pages&lt;/span&gt;&amp;nbsp;book.&lt;/p&gt;&lt;a class="btn btn--green btn--large" data-instant="" href="https://www.smashingmagazine.com/printed-books/image-optimization/" style="background: linear-gradient(rgb(158, 193, 76), rgb(65, 177, 79)) 0px 0px repeat rgb(65, 177, 79); border-radius: 11px; border: medium; box-shadow: rgb(45, 143, 57) 0px 4px; box-sizing: border-box; color: white; display: inline-block; font-family: Mija; font-size: calc(1em + 0.25vw); font-weight: 700; margin-bottom: 0px; outline: 0px; padding: 0.75em 1em; position: relative; text-align: center; text-decoration-skip-ink: auto; text-decoration: none; text-shadow: rgba(0, 0, 0, 0.25) 1px 1px 1px; text-underline-offset: 1px; top: -2px; transition: top 0.1s ease-in-out, box-shadow 0.1s ease-in-out;"&gt;Jump to table of contents&amp;nbsp;↬&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="feature-panel-right-col" style="align-items: center; box-sizing: border-box; display: flex; flex-basis: 35%; flex-shrink: 0; justify-content: center; margin: 0px; order: 0; padding: 0px; position: relative;"&gt;&lt;a class="feature-panel-image-link" data-instant="" href="https://www.smashingmagazine.com/printed-books/image-optimization/" style="background-image: none; box-sizing: border-box; color: #006fc6; max-width: 14.375rem; padding: 7px 0px 7px 2.5em; position: absolute; right: 0px; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; top: -90px; transition: scale, opacity 0.2s ease-out; width: 209.5px;"&gt;&lt;div class="feature-panel-image" style="box-sizing: border-box; margin: 0px auto; max-width: 14.375rem; transform-origin: 0px 100%; transform: rotate(-11deg); transition: 0.2s ease-out; width: 158.765625px; will-change: transform;"&gt;&lt;picture style="box-sizing: border-box;"&gt;&lt;source srcset="https://archive.smashing.media/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/2c669cf1-c6ef-4c87-9901-018b04f7871f/image-optimization-shop-cover-opt.avif" style="box-sizing: border-box;" type="image/avif"&gt;&lt;/source&gt;&lt;img alt="Feature Panel" class="feature-panel-image-img" decoding="async" height="697" loading="lazy" src="https://archive.smashing.media/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/87fd0cfa-692e-459c-b2f3-15209a1f6aa7/image-optimization-shop-cover-opt.png" style="border-radius: 11px; border-style: none; box-sizing: border-box; height: auto; max-width: 100%; position: relative;" width="480" /&gt;&lt;/picture&gt;&lt;/div&gt;&lt;/a&gt;&lt;/div&gt;&lt;/aside&gt;&lt;/div&gt;&lt;h2 id="what-local-first-actually-means-and-the-confusion-that-won-t-die" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;What “Local-First” Actually Means (And The Confusion That Won’t Die)&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;I need to clear something up because I keep having this conversation at meetups.&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Local-first is not offline-first.&lt;/span&gt;&amp;nbsp;It’s not “add a service worker and call it a day.” It’s not a synonym for PWA. I’ve seen all of these conflated in conference talks, and it drives me a little crazy.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Offline-first means your app handles network loss gracefully, but&amp;nbsp;&lt;a href="https://www.smashingmagazine.com/2019/04/cloudflare-workers-serverless/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;the server is still the source of truth&lt;/a&gt;. When the network comes back, the server wins. Cache-first (service workers caching responses) is a performance optimization. You’re serving stale data faster, which is great, but you haven’t changed who&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;owns&lt;/em&gt;&amp;nbsp;the data. PWAs are a delivery mechanism: installable, cached, push notifications. None of these is a data architecture.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Local-first is a data architecture.&lt;/span&gt;&amp;nbsp;Your user’s device holds the primary copy of their data. The app reads and writes to a local database. Renders instantly. Syncs with servers or other devices in the background. The server, when it exists, is a sync peer with some special authority (authentication, backup, access control). But it’s not the gatekeeper.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The Ink &amp;amp; Switch paper defined seven ideals, and I think they still hold up. But the one that matters most in practice, the one that changes how you build everything, is this:&lt;/p&gt;&lt;blockquote style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgba(245, 242, 240, 0.89) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-left-color: rgb(230, 228, 225); border-left-style: solid; border-left-width: 11px; border-radius: 11px; box-sizing: border-box; color: #424242; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 1.05em; font-style: italic; grid-column-end: 13; grid-column-start: 3; line-height: 1.65em; margin: 0.3em 0px 1.7em; padding-bottom: 1em; padding-top: 1em; padding: 1em calc(1.5em + 0.5vw);"&gt;The client is not a thin view requesting permission to show data. The client is a&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;node&lt;/span&gt;&amp;nbsp;in a distributed system with its own database.&lt;/blockquote&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;That distinction sounds subtle. It isn’t. It changes your entire stack.&lt;/p&gt;&lt;h2 id="be-honest-early-when-you-should-not-do-this" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Be Honest Early: When You Should Not Do This&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;I’m putting this near the top because I’ve watched too many developers (including myself, once) get excited about a new architecture and shoehorn it into projects where it doesn’t belong. I wasted about six weeks trying to make a local-first approach work for an internal analytics dashboard at a previous job. My colleague Sarah finally pulled me aside and said,&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;“The data is generated on the server. There’s nothing to replicate to the client. What are you doing?”&lt;/em&gt;&amp;nbsp;She was right.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Local-first is a bad fit when your data is primarily server-generated. Analytics dashboards, social media feeds, search results: the server&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;produces&lt;/em&gt;&amp;nbsp;this data, so the client consuming it via API requests is completely fine.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;It’s wrong for systems that need strong transactional consistency. Banking, payment processing, and inventory management. If two people try to buy the last item in stock, you need a single authoritative database making that decision with&amp;nbsp;&lt;a href="https://en.wikipedia.org/wiki/ACID" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;ACID&lt;/a&gt;&amp;nbsp;guarantees. Eventual consistency will lose you money, or worse.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;It’s overkill for simple CRUD apps with no offline or collaboration needs. If you’re building an internal admin panel used by five people in an office with good internet, adding a sync engine is over-engineering. And it’s physically impractical for massive datasets that won’t fit on client devices.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;But here’s where it shines: note-taking, document editing, collaborative design tools, project management, field apps with unreliable connectivity, basically anything where&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;data privacy is a selling point&lt;/span&gt;, as well as anything with&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;real-time collaboration&lt;/span&gt;. In other words, it’s great for&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;user-generated data&lt;/span&gt;&amp;nbsp;that benefits from instant interaction and should survive the server going down.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;One more thing I wish someone had told me earlier: you don’t have to go all-in. I’ve had the best results using local-first for&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;specific features&lt;/em&gt;&amp;nbsp;within otherwise traditional apps. Offline drafts in a blog editor. Real-time collaborative notes inside a project management tool that’s otherwise standard REST.&lt;/p&gt;&lt;blockquote class="pull-quote" style="box-sizing: border-box; color: #222222; font-family: Mija; font-size: 32px; font-weight: 700; grid-column-end: 13; grid-column-start: 3; letter-spacing: -0.75px; margin: 1.4em 0px; padding-left: 2.5em; position: relative;"&gt;&lt;p style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0px; margin-top: 0px; word-break: break-word;"&gt;&lt;a aria-label="Share on Twitter" class="pull-quote__link" href="https://twitter.com/share?text=%0aThe%20%e2%80%9cspectrum%20of%20local-first%e2%80%9d%20is%20a%20real%20thing,%20and%20starting%20with%20one%20feature%20is%20how%20I%e2%80%99d%20recommend%20anyone%20begin.%0a&amp;amp;url=https://smashingmagazine.com%2f2026%2f05%2farchitecture-local-first-web-development%2f" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: block; font-size: 1em; line-height: 42px; padding: 0px; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px;"&gt;The “spectrum of local-first” is a real thing, and starting with one feature is how I’d recommend anyone begin.&lt;/a&gt;&lt;/p&gt;&lt;div class="pull-quote__quotation" style="box-sizing: border-box; left: 0px; position: absolute; top: 5px; width: 2em;"&gt;&lt;div class="pull-quote__bg" style="background: 0% 0% repeat rgb(211, 58, 44); border-radius: 11px; box-sizing: border-box; height: 2em; padding-top: 0.15em; text-align: center; transform-origin: left bottom; transform: scale(1) rotateZ(-11deg); transition: transform 0.3s ease-out; width: 2em;"&gt;&lt;span class="pull-quote__symbol" style="box-sizing: border-box; color: white; display: block; font-size: 2.75em; line-height: 1em; transform: rotate(11deg) translateY(5px) translateX(-4px);"&gt;“&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;h2 id="replicas-not-requests" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Replicas, Not Requests&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/architecture-local-first-web-development/#replicas-not-requests" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;If you’ve used Git, you already understand the mental model.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;SVN (remember SVN?) was centralized. One server. You check out files, make changes, and commit to the server. Server down? Can’t commit. Can’t even see history.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Git gave every developer a full clone. You commit locally, branch locally, and merge locally. Push and pull when you’re ready. The remote repository is important, but it’s not the only copy of the truth.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Local-first web development is Git for application data.&lt;/span&gt;&amp;nbsp;Every client device holds a replica (full or partial) of the relevant data. Writes happen locally. Sync is push/pull in the background. Conflicts get resolved through defined merge strategies.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;I remember the first time this clicked for me in practice. I was prototyping a task board, and I wrote a function to add a task. In our old architecture, it would be:&lt;/p&gt;&lt;ol style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; counter-reset: listCounter 0; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: none; margin: 0px 0px 1.4em; max-width: 100%; padding: 0px;"&gt;&lt;li style="box-sizing: border-box; counter-increment: listCounter 1; line-height: calc(1.5em + 0.2vw); margin-bottom: 1em; padding-left: calc(1.65em + 0.7vw); position: relative; word-break: break-word;"&gt;POST to API.&lt;/li&gt;&lt;li style="box-sizing: border-box; counter-increment: listCounter 1; line-height: calc(1.5em + 0.2vw); margin-bottom: 1em; padding-left: calc(1.65em + 0.7vw); position: relative; word-break: break-word;"&gt;Wait for the response.&lt;/li&gt;&lt;li style="box-sizing: border-box; counter-increment: listCounter 1; line-height: calc(1.5em + 0.2vw); margin-bottom: 1em; padding-left: calc(1.65em + 0.7vw); position: relative; word-break: break-word;"&gt;If success, update the local state.&lt;/li&gt;&lt;li style="box-sizing: border-box; counter-increment: listCounter 1; line-height: calc(1.5em + 0.2vw); margin-bottom: 1em; padding-left: calc(1.65em + 0.7vw); position: relative; word-break: break-word;"&gt;If failure, show error toast and maybe roll back optimistic update.&lt;/li&gt;&lt;/ol&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;In the local-first version, it was: write to local SQLite, done. The UI updated instantly because it was reading from the same local database. Sync happened whenever. No loading state, no error handling for the write itself, no optimistic update logic (because there’s nothing to be “optimistic” about; the local write&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;is&lt;/em&gt;the state).&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The implications ripple through everything. You don’t need React Query or SWR for data fetching, because you’re not fetching. You don’t need Redux or Zustand for server-derived state, because the local database&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;is&lt;/em&gt;&amp;nbsp;your state. Your routing doesn’t trigger API calls. Authentication works differently because the server isn’t checking permissions on every read.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Here’s a visual comparison that might help if you’re the kind of person (like me) who thinks spatially:&lt;/p&gt;&lt;figure style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 679.765625px;"&gt;&lt;a href="https://files.smashing.media/articles/architecture-local-first-web-development/local-first-vs-traditional-architecture.png" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="Traditional request/response architecture vs. local-first architecture" decoding="async" fetchpriority="low" height="800" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/architecture-local-first-web-development/local-first-vs-traditional-architecture.png" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/architecture-local-first-web-development/local-first-vs-traditional-architecture.png 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/architecture-local-first-web-development/local-first-vs-traditional-architecture.png 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/architecture-local-first-web-development/local-first-vs-traditional-architecture.png 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/architecture-local-first-web-development/local-first-vs-traditional-architecture.png 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/architecture-local-first-web-development/local-first-vs-traditional-architecture.png 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; padding: 0.75em 2em 0.75em 0px;"&gt;Traditional request/response architecture vs. local-first architecture. (&lt;a href="https://files.smashing.media/articles/architecture-local-first-web-development/local-first-vs-traditional-architecture.png" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;On the left, every user interaction is a round-trip. Click, wait, render. On the right, reads and writes hit the local database directly. The sync server is still there, but it’s doing its work in the background. The user never waits for it. That’s the fundamental shift.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;But I’m getting ahead of myself. Before we can talk about sync and conflicts, we need to talk about where the data actually lives on the client.&lt;/p&gt;&lt;h2 id="where-data-lives-on-the-client" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Where Data Lives On The Client&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Forget&amp;nbsp;&lt;code style="background: 0% 0% repeat rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;localStorage&lt;/code&gt;. It’s synchronous (blocks the main thread), caps at 5-10 MB, and only stores strings. It’s fine for a theme preference. It’s not a database.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;IndexedDB is the workhorse that nobody loves. It’s in every browser, it’s asynchronous, it can handle hundreds of megabytes, and its API is absolutely miserable to work with. I’ve used it directly a grand total of once. Now I use it through abstractions or, more often, I don’t use it at all.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Because the real story in 2026 is SQLite running in the browser via WebAssembly.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;I know that sounds like a party trick, but it’s not. SQLite compiled to WASM, persisted to the Origin Private File System (OPFS), gives you a&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;real relational database&lt;/em&gt;&amp;nbsp;in the browser. Full SQL queries. Transactions. Indexes. The works.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;OPFS is the newer API that makes this practical. It gives web apps a sandboxed file system with high-performance synchronous access (in Web Workers), which is exactly what SQLite needs. Before OPFS, you could run SQLite in memory and manually persist to IndexedDB, which worked but was slow and fragile.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Here’s roughly what initialization looks like in a real project (I’m using&amp;nbsp;&lt;a href="https://github.com/rhashimoto/wa-sqlite" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;&lt;code style="background: 0% 0% repeat rgb(255, 242, 234); box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;wa-sqlite&lt;/code&gt;&lt;/a&gt;&amp;nbsp;here, which is the library I’ve had the best luck with):&lt;/p&gt;&lt;div class="break-out" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 14; grid-column-start: 3; margin-bottom: 1.4em; margin-top: 0px; width: 774.9375px;"&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; margin-bottom: 0px; position: relative;"&gt;&lt;pre class="language-typescript" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class="language-typescript" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;import&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt; SQLiteAPI &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;from&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'wa-sqlite'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;import&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt; OPFSCoopSyncVFS &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;from&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'wa-sqlite/src/examples/OPFSCoopSyncVFS.js'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;async&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;function&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;initDatabase&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;const&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;module&lt;/span&gt; &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;await&lt;/span&gt; SQLiteAPI&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;initialize&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;const&lt;/span&gt; vfs &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;new&lt;/span&gt; &lt;span class="token class-name" style="box-sizing: border-box; color: #0e82a9;"&gt;OPFSCoopSyncVFS&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'pm-tool-db'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;await&lt;/span&gt; vfs&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;initialize&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;module&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;const&lt;/span&gt; db &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;await&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;module&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;open_v2&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'workspace.db'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

  &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// HACK: wa-sqlite doesn't handle concurrent writes well on Safari,&lt;/span&gt;
  &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// so we serialize through a queue. See vlcn-io/wa-sqlite#247&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;await&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;module&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;exec&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;db&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; &lt;span class="token template-string" style="box-sizing: border-box;"&gt;&lt;span class="token template-punctuation string" style="box-sizing: border-box; color: #2f9c0a;"&gt;`&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;PRAGMA journal_mode=WAL&lt;/span&gt;&lt;span class="token template-punctuation string" style="box-sizing: border-box; color: #2f9c0a;"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;await&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;module&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;exec&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;db&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; &lt;span class="token template-string" style="box-sizing: border-box;"&gt;&lt;span class="token template-punctuation string" style="box-sizing: border-box; color: #2f9c0a;"&gt;`&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;
    CREATE TABLE IF NOT EXISTS tasks (
      id TEXT PRIMARY KEY,
      title TEXT NOT NULL,
      status TEXT DEFAULT 'backlog',
      assignee_id TEXT,
      project_id TEXT NOT NULL,
      position REAL DEFAULT 0,
      created_at TEXT DEFAULT (datetime('now')),
      updated_at TEXT DEFAULT (datetime('now'))
    )
  &lt;/span&gt;&lt;span class="token template-punctuation string" style="box-sizing: border-box; color: #2f9c0a;"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;return&lt;/span&gt; db&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: 0% 0% repeat rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;In production, I wrap all database access in a write queue that serializes mutations. I also log every failed write to Sentry with the full SQL statement (scrubbed of PII, obviously) because debugging database issues in a user’s browser is hell without that telemetry.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;A gotcha I wasted almost two days on: Safari’s OPFS implementation behaves differently from Chrome’s in subtle ways. Specifically, I hit a bug where&amp;nbsp;&lt;code style="background: 0% 0% repeat rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;createSyncAccessHandle()&lt;/code&gt;&amp;nbsp;would silently fail in certain iframe contexts on Safari 18. There’s no error, no exception. It just doesn’t work. I ended up falling back to IndexedDB-backed persistence on Safari, which was slower but at least functioned. (I’m told&amp;nbsp;&lt;a href="https://developer.apple.com/documentation/safari-release-notes/safari-26-release-notes" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Safari&amp;nbsp;&lt;span style="box-sizing: border-box; font-size: 15.223124px; line-height: 0; position: relative; top: -0.5em; vertical-align: baseline;"&gt;19&lt;/span&gt;⁄&lt;span style="bottom: -0.25em; box-sizing: border-box; font-size: 15.223124px; line-height: 0; position: relative; vertical-align: baseline;"&gt;26&lt;/span&gt;&lt;/a&gt;&amp;nbsp;fixes this, but I haven’t verified it yet.)&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Quick comparison of the options I’ve actually used:&lt;/p&gt;&lt;table class="tablesaw break-out" style="border-collapse: collapse; caret-color: rgb(51, 51, 51); clear: both; color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; font-variant-caps: normal; grid-column-end: 14; grid-column-start: 3; margin-bottom: 1.4em; margin-top: 0px; max-width: fit-content; width: 774.9375px;"&gt;&lt;thead style="box-sizing: border-box;"&gt;&lt;tr style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 4px; box-sizing: border-box;"&gt;&lt;th style="border-color: currentcolor currentcolor rgb(221, 221, 221); border-image: none; border-style: none none solid; border-width: medium medium 4px; box-sizing: border-box; font-family: Mija, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; padding: 0.8em 1em; text-align: left;"&gt;Storage&lt;/th&gt;&lt;th style="border-color: currentcolor currentcolor rgb(221, 221, 221); border-image: none; border-style: none none solid; border-width: medium medium 4px; box-sizing: border-box; font-family: Mija, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; padding: 0.8em 1em; text-align: left;"&gt;Good For&lt;/th&gt;&lt;th style="border-color: currentcolor currentcolor rgb(221, 221, 221); border-image: none; border-style: none none solid; border-width: medium medium 4px; box-sizing: border-box; font-family: Mija, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; padding: 0.8em 1em; text-align: left;"&gt;Watch Out For&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody style="box-sizing: border-box;"&gt;&lt;tr style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 4px; box-sizing: border-box;"&gt;&lt;td data-label="Storage" style="border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;IndexedDB&lt;/td&gt;&lt;td data-label="Good For" style="border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;Broad compatibility, moderate data&lt;/td&gt;&lt;td data-label="Watch Out For" style="border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;Terrible DX, no SQL, verbose&lt;/td&gt;&lt;/tr&gt;&lt;tr style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 4px; box-sizing: border-box;"&gt;&lt;td data-label="Storage" style="background-color: #f7f7f7; border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;OPFS + SQLite WASM&lt;/td&gt;&lt;td data-label="Good For" style="background-color: #f7f7f7; border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;Relational data, complex queries, serious apps&lt;/td&gt;&lt;td data-label="Watch Out For" style="background-color: #f7f7f7; border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;Safari quirks, ~400KB bundle addition&lt;/td&gt;&lt;/tr&gt;&lt;tr style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 4px; box-sizing: border-box;"&gt;&lt;td data-label="Storage" style="border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;PGlite (Postgres in WASM)&lt;/td&gt;&lt;td data-label="Good For" style="border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;Full Postgres compatibility on client&lt;/td&gt;&lt;td data-label="Watch Out For" style="border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;Newer, larger bundle, still maturing&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;I’ve also tried&amp;nbsp;&lt;a href="https://github.com/vlcn-io/cr-sqlite" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;&lt;code style="background: 0% 0% repeat rgb(255, 242, 234); box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;cr-sqlite&lt;/code&gt;&lt;/a&gt;, which adds CRDT column support directly to SQLite tables. Clever idea, but I found it too early-stage for production use when I evaluated it in late 2025. The merge semantics were sometimes surprising, and debugging CRDT state inside SQLite was painful. I’d revisit it later this year.&lt;/p&gt;&lt;div aria-hidden="true" class="c-friskies-box partners partners__lead partners__lead-place partners__external" data-amount="1" data-audience="non-subscriber" data-remove="true" data-rendered="true" style="align-self: center; border-radius: 11px; box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 0.9em; grid-column-end: 13; grid-column-start: 3; margin: 3em auto 1em; position: relative; width: 679.765625px;"&gt;&lt;ul style="box-sizing: border-box; list-style: outside; margin: 1em 0px 1.4em; max-width: 100%; padding-left: 0px; text-align: center;"&gt;&lt;a class="partners__native--smashing" href="https://www.smashingmagazine.com/contact/" style="border-radius: 11px; box-shadow: none; box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; transition: box-shadow 0.2s ease-in-out, top 0.1s ease-in-out;"&gt;&lt;picture style="box-sizing: border-box;"&gt;&lt;source media="(max-width: 600px)" srcset="https://www.smashingmagazine.com/images/banners/smashing-friskies-300x250.png" style="box-sizing: border-box;"&gt;&lt;/source&gt;&lt;img alt="Advertise with Smashing Magazine" decoding="async" fetchpriority="low" loading="lazy" srcset="https://www.smashingmagazine.com/images/banners/smashing-friskies-300x250.svg" style="border-style: none; box-sizing: border-box; max-width: 100%; position: relative;" width="325" /&gt;&lt;/picture&gt;&lt;/a&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 id="the-part-that-s-actually-hard" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;The Part That’s Actually Hard&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Storing data locally is a solved problem. Syncing it reliably across devices and users is where you earn your gray hairs.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;When multiple replicas can independently read and write, you need a mechanism to reconcile changes. There are basically four approaches, and I’ve used three of them.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;CRDTs (Conflict-Free Replicated Data Types)&lt;/span&gt;&amp;nbsp;are data structures designed so that concurrent edits can always be merged without conflicts, mathematically guaranteed. Yjs is the most popular implementation in JavaScript, and it’s genuinely excellent for real-time collaborative text editing. I used it to build a collaborative document editor at my last company, and the experience was mostly good, though I’ll get into the pain points in the conflict resolution section.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Here’s what setting up a shared Yjs document looks like in practice:&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class="language-typescript" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class="language-typescript" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;import&lt;/span&gt; &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;*&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;as&lt;/span&gt; &lt;span class="token constant" style="box-sizing: border-box; color: #c92c2c;"&gt;Y&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;from&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'yjs'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;import&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt; WebsocketProvider &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;from&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'y-websocket'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;const&lt;/span&gt; ydoc &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;new&lt;/span&gt; &lt;span class="token class-name" style="box-sizing: border-box; color: #0e82a9;"&gt;&lt;span class="token constant" style="box-sizing: border-box; color: #c92c2c;"&gt;Y&lt;/span&gt;&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;Doc&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;const&lt;/span&gt; provider &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;new&lt;/span&gt; &lt;span class="token class-name" style="box-sizing: border-box; color: #0e82a9;"&gt;WebsocketProvider&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;
  &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'wss://sync.our-app.dev'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt;
  &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'workspace-a1b2c3d4'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt;
  ydoc
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;const&lt;/span&gt; tasks &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; ydoc&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;getMap&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'tasks'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

&lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// Add a task&lt;/span&gt;
&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;const&lt;/span&gt; task &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;new&lt;/span&gt; &lt;span class="token class-name" style="box-sizing: border-box; color: #0e82a9;"&gt;&lt;span class="token constant" style="box-sizing: border-box; color: #c92c2c;"&gt;Y&lt;/span&gt;&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;Map&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
task&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;set&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'title'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'Review Q3 roadmap draft'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
task&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;set&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'completed'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; &lt;span class="token boolean" style="box-sizing: border-box; color: #c92c2c;"&gt;false&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
task&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;set&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'assignee'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'maria'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// TODO: type this properly once; yjs exports better TS types&lt;/span&gt;
&lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// for nested maps. For now, this works fine.&lt;/span&gt;
tasks&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;set&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'f47ac10b-58cc-4372-a567-0e02b2c3d479'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; task &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;as&lt;/span&gt; &lt;span class="token builtin" style="box-sizing: border-box; color: #2f9c0a;"&gt;any&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

tasks&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;observeDeep&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// Re-render UI. In practice, I debounce this to ~16ms&lt;/span&gt;
  &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// because observeDeep fires a LOT during active collaboration&lt;/span&gt;
  &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;renderTaskList&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;tasks&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;toJSON&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: 0% 0% repeat rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;a href="https://github.com/automerge/automerge" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Automerge&lt;/a&gt;&amp;nbsp;is the other major CRDT library, backed by Rust and with a document-oriented model. I’ve used it less, but I know teams who swear by it.&amp;nbsp;&lt;a href="https://github.com/loro-dev/loro" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Loro&lt;/a&gt;&amp;nbsp;is newer, Rust-based, and claims better performance. I haven’t shipped anything with Loro yet.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Database replication&lt;/span&gt;&amp;nbsp;is the other big approach, and honestly, for most apps that don’t need Google Docs-style real-time text editing, I think it’s the better choice. The idea is straightforward: replicate rows between a server database (Postgres) and a client database (SQLite) with a sync engine managing the plumbing.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;a href="https://www.powersync.com/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;PowerSync&lt;/a&gt;&amp;nbsp;does this well. It gives you one-way replication from Postgres to client SQLite with a write-back path for mutations. ElectricSQL is more ambitious, going for full active-active sync between Postgres and SQLite. I’ve used PowerSync in production and&amp;nbsp;&lt;a href="https://electric-sql.com/docs/intro" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;ElectricSQL&lt;/a&gt;&amp;nbsp;in prototypes. PowerSync felt more stable when I evaluated them both in early 2026, but ElectricSQL’s approach is more powerful if they nail the execution.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;a href="https://github.com/aspen-cloud/triplit" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Triplit&lt;/a&gt;&amp;nbsp;takes a different angle entirely: it’s a full-stack database with sync built in, so you don’t think about “client DB” and “server DB” separately. I haven’t tried it beyond a weekend prototype, but the developer experience was surprisingly nice.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Event sourcing&lt;/span&gt;&amp;nbsp;(syncing a log of mutations rather than the current state) is the approach&amp;nbsp;&lt;a href="https://livestore.dev/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;LiveStore&lt;/a&gt;&amp;nbsp;takes. I find it intellectually appealing and occasionally useful, but in practice, I’ve found that reconstructing state from an event log adds complexity that most apps don’t need. My controversial opinion: Event sourcing is over-recommended for application development. It’s great for audit logs and certain domains, but for a task board? Just sync the rows.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Not everyone will agree with that. I know event sourcing has passionate advocates, and I’ve been told I’m wrong about this at least twice at conferences. Maybe I just haven’t built the right app for it yet.&lt;/p&gt;&lt;h2 id="conflicts-the-thing-everyone-s-afraid-of" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Conflicts: The Thing Everyone’s Afraid Of&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;I used to think conflict resolution was a terrifying, unsolvable problem. After building three apps that handle it, I’d revise that to: it’s a&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;manageable&lt;/em&gt;&amp;nbsp;problem that requires you to think carefully about your specific data model, and most developers overthink it.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Conflicts happen when two replicas modify the same data without seeing each other’s changes. User A edits a task title on their phone while offline. User B edits the same title on their laptop. Both come back online. Now what?&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;My first attempt at handling this was embarrassingly naive:&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class="language-typescript" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class="language-typescript" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// My first try. Don't do this.&lt;/span&gt;
&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;function&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;resolveConflict&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;local&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; &lt;span class="token builtin" style="box-sizing: border-box; color: #2f9c0a;"&gt;any&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; remote&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; &lt;span class="token builtin" style="box-sizing: border-box; color: #2f9c0a;"&gt;any&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// just... take the remote one? sure?&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;return&lt;/span&gt; remote&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: 0% 0% repeat rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The problem is obvious: local changes get silently dropped. User A edits a title, syncs, and their edit vanishes. They don’t even know it happened.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;What actually works for most cases is&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;last-write-wins (LWW)&lt;/span&gt;&amp;nbsp;at the&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;field&lt;/em&gt;&amp;nbsp;level, not the record level. If User A changes the title and User B changes the due date, you keep both changes because they touched different fields. You only have a real conflict when both modified the same field, and then you pick the later timestamp.&lt;/p&gt;&lt;div class="break-out" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 14; grid-column-start: 3; margin-bottom: 1.4em; margin-top: 0px; width: 774.9375px;"&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; margin-bottom: 0px; position: relative;"&gt;&lt;pre class="language-typescript" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class="language-typescript" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;interface&lt;/span&gt; &lt;span class="token class-name" style="box-sizing: border-box; color: #0e82a9;"&gt;FieldValue&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  value&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; &lt;span class="token builtin" style="box-sizing: border-box; color: #2f9c0a;"&gt;string&lt;/span&gt; &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;|&lt;/span&gt; &lt;span class="token builtin" style="box-sizing: border-box; color: #2f9c0a;"&gt;number&lt;/span&gt; &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;|&lt;/span&gt; &lt;span class="token builtin" style="box-sizing: border-box; color: #2f9c0a;"&gt;boolean&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// ISO timestamp with enough precision to break most ties&lt;/span&gt;
  updatedAt&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; &lt;span class="token builtin" style="box-sizing: border-box; color: #2f9c0a;"&gt;string&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// Client ID as tiebreaker when timestamps match.&lt;/span&gt;
  &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// This happens more often than you'd think.&lt;/span&gt;
  clientId&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; &lt;span class="token builtin" style="box-sizing: border-box; color: #2f9c0a;"&gt;string&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;

&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;function&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;pickWinner&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;a&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; FieldValue&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; b&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; FieldValue&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; FieldValue &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;const&lt;/span&gt; timeA &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;new&lt;/span&gt; &lt;span class="token class-name" style="box-sizing: border-box; color: #0e82a9;"&gt;Date&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;a&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;updatedAt&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;getTime&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;const&lt;/span&gt; timeB &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;new&lt;/span&gt; &lt;span class="token class-name" style="box-sizing: border-box; color: #0e82a9;"&gt;Date&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;b&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;updatedAt&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;getTime&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;if&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;timeA &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;!==&lt;/span&gt; timeB&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;return&lt;/span&gt; timeA &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;&amp;gt;&lt;/span&gt; timeB &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;?&lt;/span&gt; a &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; b&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// Deterministic tiebreaker when timestamps match&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;return&lt;/span&gt; a&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;clientId &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;&amp;gt;&lt;/span&gt; b&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;clientId &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;?&lt;/span&gt; a &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; b&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;

&lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// In practice, I apply this per-field across the whole record.&lt;/span&gt;
&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;function&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;mergeTask&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;local&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; Record&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;&amp;lt;&lt;/span&gt;&lt;span class="token builtin" style="box-sizing: border-box; color: #2f9c0a;"&gt;string&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; FieldValue&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;&amp;gt;&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; remote&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; Record&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;&amp;lt;&lt;/span&gt;&lt;span class="token builtin" style="box-sizing: border-box; color: #2f9c0a;"&gt;string&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; FieldValue&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;&amp;gt;&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;const&lt;/span&gt; merged&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; Record&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;&amp;lt;&lt;/span&gt;&lt;span class="token builtin" style="box-sizing: border-box; color: #2f9c0a;"&gt;string&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; FieldValue&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;&amp;gt;&lt;/span&gt; &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;const&lt;/span&gt; allKeys &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;new&lt;/span&gt; &lt;span class="token class-name" style="box-sizing: border-box; color: #0e82a9;"&gt;Set&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;[&lt;/span&gt;&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;...&lt;/span&gt;Object&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;keys&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;local&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;...&lt;/span&gt;Object&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;keys&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;remote&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;]&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;for&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;const&lt;/span&gt; key &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;of&lt;/span&gt; allKeys&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
    &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;if&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;!&lt;/span&gt;local&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;[&lt;/span&gt;key&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;]&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt; merged&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;[&lt;/span&gt;key&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;]&lt;/span&gt; &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; remote&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;[&lt;/span&gt;key&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;]&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;continue&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
    &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;if&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;!&lt;/span&gt;remote&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;[&lt;/span&gt;key&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;]&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt; merged&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;[&lt;/span&gt;key&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;]&lt;/span&gt; &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; local&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;[&lt;/span&gt;key&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;]&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;continue&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
    merged&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;[&lt;/span&gt;key&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;]&lt;/span&gt; &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;pickWinner&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;local&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;[&lt;/span&gt;key&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;]&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; remote&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;[&lt;/span&gt;key&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;]&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;return&lt;/span&gt; merged&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: 0% 0% repeat rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;In our production app, this handles about 95% of conflicts without any user-visible issues. For the remaining cases (two people editing the same text field), LWW means one person’s edit silently wins. For a task title? Honestly, that’s usually fine. For a document body? No. That’s where CRDTs earn their keep.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;But there’s a subtler problem I didn’t appreciate until I hit it:&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;semantic conflicts&lt;/span&gt;. Data merges cleanly at the structural level, but the result is nonsensical. Two users, both offline, book the same 2 PM meeting slot with different meetings. Field-level merge accepts both writes because they’re writing to different records. No structural conflict. But you’ve got a double-booking, and your merge function has no idea that’s a problem.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Semantic conflicts require application-level validation, and that has to happen on the server during sync. Your sync engine merges the data structurally, but&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;your&lt;/em&gt;server needs to check domain invariants before accepting the result. The approach I’ve landed on (after getting it wrong twice) is: validate on the server during the write-back phase, but&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;flag&lt;/em&gt;&amp;nbsp;violations rather than silently rejecting them.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Here’s what I mean. When the client pushes mutations to the server during sync, the server runs them through a constraint validation layer before applying them to Postgres:&lt;/p&gt;&lt;div class="break-out" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 14; grid-column-start: 3; margin-bottom: 1.4em; margin-top: 0px; width: 774.9375px;"&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; margin-bottom: 0px; position: relative;"&gt;&lt;pre class="language-typescript" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class="language-typescript" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;interface&lt;/span&gt; &lt;span class="token class-name" style="box-sizing: border-box; color: #0e82a9;"&gt;SyncViolation&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;type&lt;/span&gt;&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'scheduling_conflict'&lt;/span&gt; &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;|&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'capacity_exceeded'&lt;/span&gt; &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;|&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'stale_assignment'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  recordId&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; &lt;span class="token builtin" style="box-sizing: border-box; color: #2f9c0a;"&gt;string&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  description&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; &lt;span class="token builtin" style="box-sizing: border-box; color: #2f9c0a;"&gt;string&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// The conflicting records so the client can show context&lt;/span&gt;
  conflictingRecords&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; &lt;span class="token builtin" style="box-sizing: border-box; color: #2f9c0a;"&gt;string&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;[&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;]&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// When was this violation detected&lt;/span&gt;
  detectedAt&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; &lt;span class="token builtin" style="box-sizing: border-box; color: #2f9c0a;"&gt;string&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;

&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;async&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;function&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;validateSyncBatch&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;
  mutations&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; SyncMutation&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;[&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;]&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt;
  serverDb&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; Database
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; &lt;span class="token builtin" style="box-sizing: border-box; color: #2f9c0a;"&gt;Promise&lt;/span&gt;&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;&amp;lt;&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt; accepted&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; SyncMutation&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;[&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;]&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt; violations&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; SyncViolation&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;[&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;]&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;&amp;gt;&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;const&lt;/span&gt; accepted&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; SyncMutation&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;[&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;]&lt;/span&gt; &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;[&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;]&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;const&lt;/span&gt; violations&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; SyncViolation&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;[&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;]&lt;/span&gt; &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;[&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;]&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;for&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;const&lt;/span&gt; mutation &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;of&lt;/span&gt; mutations&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
    &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;if&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;mutation&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;table &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;===&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'calendar_events'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
      &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// Check for double-booking&lt;/span&gt;
      &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;const&lt;/span&gt; overlapping &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;await&lt;/span&gt; serverDb&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;query&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;
        &lt;span class="token template-string" style="box-sizing: border-box;"&gt;&lt;span class="token template-punctuation string" style="box-sizing: border-box; color: #2f9c0a;"&gt;`&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;SELECT id, title FROM calendar_events
         WHERE room_id = ? AND id != ?
         AND start_time &amp;lt; ? AND end_time &amp;gt; ?&lt;/span&gt;&lt;span class="token template-punctuation string" style="box-sizing: border-box; color: #2f9c0a;"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt;
        &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;[&lt;/span&gt;mutation&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;data&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;room_id&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; mutation&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;data&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;id&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt;
         mutation&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;data&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;end_time&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; mutation&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;data&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;start_time&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;]&lt;/span&gt;
      &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

      &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;if&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;overlapping&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;length &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;&amp;gt;&lt;/span&gt; &lt;span class="token number" style="box-sizing: border-box; color: #c92c2c;"&gt;0&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
        violations&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;push&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
          &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;type&lt;/span&gt;&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'scheduling_conflict'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt;
          recordId&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; mutation&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;data&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;id&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt;
          description&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; &lt;span class="token template-string" style="box-sizing: border-box;"&gt;&lt;span class="token template-punctuation string" style="box-sizing: border-box; color: #2f9c0a;"&gt;`&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;Conflicts with "&lt;/span&gt;&lt;span class="token interpolation" style="box-sizing: border-box;"&gt;&lt;span class="token interpolation-punctuation punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;${&lt;/span&gt;overlapping&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;[&lt;/span&gt;&lt;span class="token number" style="box-sizing: border-box; color: #c92c2c;"&gt;0&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;]&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;title&lt;span class="token interpolation-punctuation punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;"&lt;/span&gt;&lt;span class="token template-punctuation string" style="box-sizing: border-box; color: #2f9c0a;"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt;
          conflictingRecords&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; overlapping&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;map&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;r &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&amp;gt;&lt;/span&gt; r&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;id&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt;
          detectedAt&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;new&lt;/span&gt; &lt;span class="token class-name" style="box-sizing: border-box; color: #0e82a9;"&gt;Date&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;toISOString&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;
        &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
        &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// Still accept the write, but flag it&lt;/span&gt;
        &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// The alternative is rejecting it, but then the user's&lt;/span&gt;
        &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// local state and server state diverge, and that's worse&lt;/span&gt;
        accepted&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;push&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;mutation&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
        &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;continue&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
      &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
    &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
    accepted&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;push&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;mutation&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;

  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;return&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt; accepted&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; violations &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: 0% 0% repeat rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The key decision here — and I went back and forth on this — is that we&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;accept&lt;/em&gt;&amp;nbsp;the conflicting write and flag it, rather than rejecting it outright. If you reject it, the user’s local database has a record that the server refuses to acknowledge, and now you’re in a state divergence situation that’s genuinely hard to recover from. I tried the rejection approach first, and it led to ghost records on the client that users couldn’t delete because they didn’t exist on the server. Nightmare.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;So instead, the server accepts the write, stores the violation, and syncs the violation back to the client. The client shows a non-blocking notification:&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;“Your meeting ‘Q3 Planning’ conflicts with ‘Design Review’ in Room B at 2 PM. Tap to resolve.”&lt;/em&gt;The user taps, sees both meetings, and picks one to reschedule or cancel. The resolution is a normal write that syncs back.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Is this perfect? No. There’s a window between when the violation is created and when the user resolves it, where both conflicting records exist. For meeting rooms, that’s tolerable. For something like inventory management where two people “buy” the last item, that window is unacceptable, and that’s exactly why I said earlier that local-first is wrong for systems requiring strong transactional consistency.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;I’m still iterating on this pattern. The violation table grows if users ignore notifications (we expire them after 72 hours, which feels arbitrary). And deciding&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;which&lt;/em&gt;&amp;nbsp;invariants to validate on the server requires you to essentially maintain a parallel set of business rules outside your client-side application logic. It’s not elegant. But it works, and it’s the best approach I’ve found for the class of apps I’m building. If you’ve built something cleaner, I genuinely want to hear about it.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;For CRDTs like Yjs, conflict resolution at the character level (for text) works remarkably well. Two people typing in the same paragraph will see both sets of characters appear in a sensible order. But CRDT merging of structured data (maps, arrays, nested objects) can produce results that surprise you. I once watched a Yjs-backed task list duplicate items after a merge because two users had reordered the same list offline, and the CRDT’s list merge semantics interleaved their orderings. Technically correct. Practically confusing. We ended up adding a post-merge de-duplication step, which felt like a hack but solved the problem.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;When should you surface conflicts to the user, Git-style? In my experience, almost never for typical app data. Users don’t want to resolve merge conflicts. They want the app to figure it out. The exception is high-stakes content: legal documents, medical records, anything where silently dropping an edit could cause real harm.&lt;/p&gt;&lt;h2 id="the-tools-right-now" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;The Tools Right Now&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;I’m going to give you my honest read on the tools available as of mid-2026, with the caveat that this space is moving fast enough that some of this might be outdated by the time you read it.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Yjs&lt;/span&gt;&amp;nbsp;is the most mature CRDT library. Production-ready, huge community, integrates with most collaborative editors (TipTap, BlockNote, Lexical). If you need real-time collaborative editing, start here.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Automerge&lt;/span&gt;&amp;nbsp;is solid, Rust-backed, and takes a more document-oriented approach than Yjs. I’ve seen it used well in apps where the data model fits a document metaphor. Fewer integrations than Yjs, but the core is well-engineered.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;PowerSync&lt;/span&gt;&amp;nbsp;is what I’d recommend for teams that have an existing Postgres back-end and want to add offline support. It’s production-ready, the docs are good, and the mental model (Postgres syncs to client SQLite, client writes go through a defined upload path) is easy to reason about. In our app, initial sync for a workspace with around 5,000 tasks takes about 1.2 seconds on a decent connection and about 3.5 seconds on a throttled 3G simulation. That was acceptable for us.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;ElectricSQL&lt;/span&gt;&amp;nbsp;is going for something more ambitious: true active-active replication between Postgres and SQLite, with “shapes” defining what data syncs to which client. I want this to succeed because the developer experience in prototypes was excellent. But when I evaluated it for production in February 2026, I hit enough rough edges (particularly around shape management and reconnection behavior) that I went with PowerSync instead. I plan to revisit it.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Triplit&lt;/span&gt;&amp;nbsp;impressed me in a weekend prototype. Full-stack database with sync built in, nice TypeScript API. I haven’t stress-tested it with real production load, and I’d want to before committing.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;a href="https://zero.rocicorp.dev/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Zero&lt;/span&gt;&lt;/a&gt;&amp;nbsp;(from Rocicorp, the Replicache people) is interesting because it takes a query-based approach to sync, which is different from the row-replication model. Replicache was sunset in favor of Zero, which tells you something about how fast approaches are evolving in this space. Worth watching, but I wouldn’t build on it yet for a production app.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;a href="https://tinybase.org/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;TinyBase&lt;/span&gt;&lt;/a&gt;&amp;nbsp;is a lightweight reactive store that’s great for smaller apps or prototyping. I used it for a personal side project (a reading tracker) and liked it a lot. Not sure I’d use it for a team-scale product.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;a href="https://pglite.dev/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;PGlite&lt;/span&gt;&lt;/a&gt;&amp;nbsp;(Postgres compiled to WASM) is wild. Same SQL dialect on client and server. Combined with ElectricSQL, you could theoretically run identical queries everywhere. I think this is where things are heading long-term, but PGlite’s bundle size and memory footprint are still concerns for mobile browsers.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;One thing the Replicache sunset taught me: don’t bet your architecture on a single tool from a small company without a fallback plan. I keep my sync layer abstracted enough that I could swap engines in a few weeks, not months. I know that sounds like premature abstraction, but in a space this young, I think it’s just prudence.&lt;/p&gt;&lt;div aria-hidden="true" class="c-friskies-box partners partners__lead partners__lead-place partners__external" data-amount="1" data-audience="non-subscriber" data-remove="true" style="align-self: center; border-radius: 11px; box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 0.9em; grid-column-end: 13; grid-column-start: 3; margin: 3em auto 1em; position: relative; width: 679.765625px;"&gt;&lt;/div&gt;&lt;h2 id="building-a-real-app-architecture-auth-and-migrations" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Building A Real App: Architecture, Auth, And Migrations&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/architecture-local-first-web-development/#building-a-real-app-architecture-auth-and-migrations" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;I want to walk through how I actually structure a local-first app in practice, because the layer diagrams you see in blog posts rarely match what the code looks like.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;My current stack for a collaborative project management tool looks like this:&lt;/p&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;UI:&lt;/span&gt;&amp;nbsp;React components that never call&amp;nbsp;&lt;code style="background: 0% 0% repeat rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;fetch()&lt;/code&gt;&amp;nbsp;for data reads.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Query layer:&lt;/span&gt;&amp;nbsp;&lt;code style="background: 0% 0% repeat rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;useLiveQuery&lt;/code&gt;&amp;nbsp;hooks that subscribe to the local SQLite database and re-render automatically when data changes.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Local database:&lt;/span&gt;&amp;nbsp;SQLite via wa-sqlite, persisted to OPFS.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Mutation layer:&lt;/span&gt;&amp;nbsp;Plain&amp;nbsp;&lt;code style="background: 0% 0% repeat rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;INSERT&lt;/code&gt;/&lt;code style="background: 0% 0% repeat rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;UPDATE&lt;/code&gt;/&lt;code style="background: 0% 0% repeat rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;DELETE&lt;/code&gt;&amp;nbsp;statements against local SQLite.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Sync:&lt;/span&gt;&amp;nbsp;PowerSync managing replication between local SQLite and our Postgres back-end.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Server:&lt;/span&gt;&amp;nbsp;Postgres, a Node.js auth service, and a small sync validation layer.&lt;/li&gt;&lt;/ul&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The component code ends up looking almost absurdly simple compared to what I used to write:&lt;/p&gt;&lt;div class="break-out" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 14; grid-column-start: 3; margin-bottom: 1.4em; margin-top: 0px; width: 774.9375px;"&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; margin-bottom: 0px; position: relative;"&gt;&lt;pre class="language-typescript" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class="language-typescript" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;import&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt; useLiveQuery &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;from&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'@powersync/react'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;import&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt; db &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;from&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'../lib/database'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;function&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;TaskBoard&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt; projectId &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt; projectId&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; &lt;span class="token builtin" style="box-sizing: border-box; color: #2f9c0a;"&gt;string&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;const&lt;/span&gt; tasks &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;useLiveQuery&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;
    &lt;span class="token template-string" style="box-sizing: border-box;"&gt;&lt;span class="token template-punctuation string" style="box-sizing: border-box; color: #2f9c0a;"&gt;`&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;SELECT * FROM tasks WHERE project_id = ? AND archived = 0 ORDER BY position&lt;/span&gt;&lt;span class="token template-punctuation string" style="box-sizing: border-box; color: #2f9c0a;"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt;
    &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;[&lt;/span&gt;projectId&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;]&lt;/span&gt;
  &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;async&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;function&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;addTask&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;title&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; &lt;span class="token builtin" style="box-sizing: border-box; color: #2f9c0a;"&gt;string&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
    &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;await&lt;/span&gt; db&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;execute&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;
      &lt;span class="token template-string" style="box-sizing: border-box;"&gt;&lt;span class="token template-punctuation string" style="box-sizing: border-box; color: #2f9c0a;"&gt;`&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;INSERT INTO tasks (id, title, project_id, position, created_at)
       VALUES (?, ?, ?, ?, datetime('now'))&lt;/span&gt;&lt;span class="token template-punctuation string" style="box-sizing: border-box; color: #2f9c0a;"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt;
      &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;[&lt;/span&gt;crypto&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;randomUUID&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; title&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; projectId&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; tasks&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;length&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;]&lt;/span&gt;
    &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
    &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// That's it. useLiveQuery picks up the change automatically.&lt;/span&gt;
    &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// No invalidation, no refetch, no loading state.&lt;/span&gt;
  &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;

  &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// No isLoading check. Data is local. It's always there after the first sync.&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;return&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;
    &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;&amp;lt;&lt;/span&gt;div&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;tasks&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;map&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;task &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;&amp;lt;&lt;/span&gt;TaskCard key&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;task&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;id&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt; task&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;task&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt; &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;/&lt;/span&gt;&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;&amp;gt;&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
      &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;&amp;lt;&lt;/span&gt;NewTaskInput onSubmit&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;addTask&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt; &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;/&lt;/span&gt;&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;&amp;lt;&lt;/span&gt;&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;/&lt;/span&gt;div&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: 0% 0% repeat rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Compare that to the React Query + REST equivalent, which would be at least twice the code and include loading states, error states, optimistic update logic with rollback, and cache invalidation. I don’t miss it.&lt;/p&gt;&lt;h3 id="auth-in-a-local-first-world" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;AUTH IN A LOCAL-FIRST WORLD&amp;nbsp;&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Authentication works roughly the same as traditional apps: JWT tokens, OAuth flows, and session management. The token authenticates the sync connection rather than every individual request. Offline access works because the data is already local. The user was authenticated when the data was originally synced.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Authorization is trickier, and I think most local-first articles under-explain this. You cannot sync your entire database to every client and rely on client-side code to hide unauthorized data. Someone will open DevTools, find the local SQLite file, and see everything. The client is not a trust boundary.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;You enforce authorization at the sync layer. PowerSync has “sync rules” that define which rows go to which clients. ElectricSQL has “shapes.” Either way, the server only sends data that the user is authorized to see. When the client sends writes back, the server validates them against authorization rules before applying them to Postgres. If a user tries to modify something they shouldn’t, the server rejects it during sync.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;I also want to mention&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;end-to-end encryption (E2EE)&lt;/span&gt;, because it pairs naturally with local-first. Since data lives on the client, you can encrypt it before sync. The server stores and relays encrypted blobs it can’t read. Apps like Anytype do this. We haven’t implemented E2EE in our current app, but it’s on the roadmap for when we handle more sensitive data.&lt;/p&gt;&lt;h3 id="schema-migrations-on-a-thousand-devices" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;SCHEMA MIGRATIONS ON A THOUSAND DEVICES&amp;nbsp;&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;This one caught me off guard the first time. On the server, you run a migration against one database you control. On the client, every user has their own database that might be running any version of your schema, depending on when they last opened the app.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;I use a simple migration runner that checks a version number at app startup:&lt;/p&gt;&lt;div class="break-out" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 14; grid-column-start: 3; margin-bottom: 1.4em; margin-top: 0px; width: 774.9375px;"&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; margin-bottom: 0px; position: relative;"&gt;&lt;pre class="language-typescript" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class="language-typescript" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;const&lt;/span&gt; &lt;span class="token constant" style="box-sizing: border-box; color: #c92c2c;"&gt;MIGRATIONS&lt;/span&gt; &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;[&lt;/span&gt;
  &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
    version&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; &lt;span class="token number" style="box-sizing: border-box; color: #c92c2c;"&gt;1&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt;
    sql&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; &lt;span class="token template-string" style="box-sizing: border-box;"&gt;&lt;span class="token template-punctuation string" style="box-sizing: border-box; color: #2f9c0a;"&gt;`&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;
      CREATE TABLE IF NOT EXISTS tasks (
        id TEXT PRIMARY KEY,
        title TEXT NOT NULL,
        status TEXT DEFAULT 'backlog',
        project_id TEXT NOT NULL,
        created_at TEXT DEFAULT (datetime('now'))
      );
    &lt;/span&gt;&lt;span class="token template-punctuation string" style="box-sizing: border-box; color: #2f9c0a;"&gt;`&lt;/span&gt;&lt;/span&gt;
  &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt;
  &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
    version&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; &lt;span class="token number" style="box-sizing: border-box; color: #c92c2c;"&gt;2&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt;
    &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// Added priority and due_date in sprint 4&lt;/span&gt;
    sql&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; &lt;span class="token template-string" style="box-sizing: border-box;"&gt;&lt;span class="token template-punctuation string" style="box-sizing: border-box; color: #2f9c0a;"&gt;`&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;
      ALTER TABLE tasks ADD COLUMN priority INTEGER DEFAULT 0;
      ALTER TABLE tasks ADD COLUMN due_date TEXT;
    &lt;/span&gt;&lt;span class="token template-punctuation string" style="box-sizing: border-box; color: #2f9c0a;"&gt;`&lt;/span&gt;&lt;/span&gt;
  &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt;
  &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
    version&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; &lt;span class="token number" style="box-sizing: border-box; color: #c92c2c;"&gt;3&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt;
    &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// Denormalized assignee name for offline display.&lt;/span&gt;
    &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// Yes, I know this is a trade-off. The JOIN was killing&lt;/span&gt;
    &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// performance on low-end Android devices.&lt;/span&gt;
    sql&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; &lt;span class="token template-string" style="box-sizing: border-box;"&gt;&lt;span class="token template-punctuation string" style="box-sizing: border-box; color: #2f9c0a;"&gt;`&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;
      ALTER TABLE tasks ADD COLUMN assignee_name TEXT DEFAULT '';
    &lt;/span&gt;&lt;span class="token template-punctuation string" style="box-sizing: border-box; color: #2f9c0a;"&gt;`&lt;/span&gt;&lt;/span&gt;
  &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;]&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;async&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;function&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;runMigrations&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;db&lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; Database&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;await&lt;/span&gt; db&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;execute&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token template-string" style="box-sizing: border-box;"&gt;&lt;span class="token template-punctuation string" style="box-sizing: border-box; color: #2f9c0a;"&gt;`&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;
    CREATE TABLE IF NOT EXISTS _schema_version (version INTEGER)
  &lt;/span&gt;&lt;span class="token template-punctuation string" style="box-sizing: border-box; color: #2f9c0a;"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;const&lt;/span&gt; rows &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;await&lt;/span&gt; db&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;execute&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'SELECT version FROM _schema_version'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;const&lt;/span&gt; currentVersion &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; rows&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;length &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;&amp;gt;&lt;/span&gt; &lt;span class="token number" style="box-sizing: border-box; color: #c92c2c;"&gt;0&lt;/span&gt; &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;?&lt;/span&gt; rows&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;[&lt;/span&gt;&lt;span class="token number" style="box-sizing: border-box; color: #c92c2c;"&gt;0&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;]&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;version &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; &lt;span class="token number" style="box-sizing: border-box; color: #c92c2c;"&gt;0&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;for&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;const&lt;/span&gt; migration &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;of&lt;/span&gt; &lt;span class="token constant" style="box-sizing: border-box; color: #c92c2c;"&gt;MIGRATIONS&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
    &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;if&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;migration&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;version &lt;span class="token operator" style="background: 0% 0% repeat rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;&amp;gt;&lt;/span&gt; currentVersion&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
      &lt;span class="token builtin" style="box-sizing: border-box; color: #2f9c0a;"&gt;console&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;log&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token template-string" style="box-sizing: border-box;"&gt;&lt;span class="token template-punctuation string" style="box-sizing: border-box; color: #2f9c0a;"&gt;`&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;Migrating local DB to v&lt;/span&gt;&lt;span class="token interpolation" style="box-sizing: border-box;"&gt;&lt;span class="token interpolation-punctuation punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;${&lt;/span&gt;migration&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;version&lt;span class="token interpolation-punctuation punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="token template-punctuation string" style="box-sizing: border-box; color: #2f9c0a;"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
      &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;await&lt;/span&gt; db&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;execute&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'BEGIN'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
      &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;try&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
        &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;await&lt;/span&gt; db&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;execute&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;migration&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;sql&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
        &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;await&lt;/span&gt; db&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;execute&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;
          &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'INSERT OR REPLACE INTO _schema_version (rowid, version) VALUES (1, ?)'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt;
          &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;[&lt;/span&gt;migration&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;version&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;]&lt;/span&gt;
        &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
        &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;await&lt;/span&gt; db&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;execute&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'COMMIT'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
      &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;catch&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;err&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
        &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;await&lt;/span&gt; db&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;execute&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'ROLLBACK'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
        &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// In production, this fires a Sentry alert with the&lt;/span&gt;
        &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// migration version and error details&lt;/span&gt;
        &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;throw&lt;/span&gt; err&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
      &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
    &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
  &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: 0% 0% repeat rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Design your migrations to be additive.&lt;/span&gt;&amp;nbsp;New columns with defaults. New tables. Don’t rename or drop columns unless you absolutely must, because users running old app versions will still be syncing data, and your server needs to handle the mismatch. I learned this the hard way when I dropped a column that an older client was still writing to, which caused silent sync failures for about 200 users over a weekend. Not fun.&lt;/p&gt;&lt;h2 id="if-i-were-starting-a-new-project-today" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;If I Were Starting A New Project Today&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;I get asked this a lot, so here’s my current answer. It changes every six months or so.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;For a collaborative app with real-time features and offline support, I’d start with:&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;React&lt;/span&gt;&amp;nbsp;on the front end,&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;PowerSync&lt;/span&gt;&amp;nbsp;for sync,&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;SQLite via wa-sqlite&lt;/span&gt;&amp;nbsp;on the client (persisted to OPFS with IndexedDB fallback for Safari), and&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Supabase&lt;/span&gt;&amp;nbsp;(which gives me Postgres, auth, and row-level security out of the box). I’d use&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Yjs&lt;/span&gt;&amp;nbsp;only if I needed rich text collaboration, and I’d avoid it if I didn’t, because CRDTs add meaningful complexity to your data model.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;For a simpler app where I mostly need offline support and instant reads but collaboration is secondary, I might skip the sync engine entirely and just use a local SQLite database with a custom sync layer that pushes/pulls from a REST API. I know that sounds like reinventing the wheel, but for simple cases, a custom sync that you fully understand is better than a general-purpose sync engine that adds concepts you don’t need.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;I would not currently use ElectricSQL or Zero for production, not because they’re bad, but because I want another 6-12 months of maturity before I’d trust them for something I’m on-call for. I’ve been burned before by building on early-stage infrastructure (I was an early&amp;nbsp;&lt;a href="https://docs.meteor.com/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Meteor&lt;/a&gt;&amp;nbsp;adopter, if that tells you anything) and I’m more cautious now about where I accept novelty risk.&lt;/p&gt;&lt;h2 id="performance-what-s-actually-fast-and-what-hurts" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Performance: What’s Actually Fast And What Hurts&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Reads are instant. That’s not marketing. Querying a local SQLite database for a list of 500 tasks takes under two milliseconds on my M2 MacBook and about eight milliseconds on a mid-range Android phone. No network. No spinner. No loading state.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Writes are instant, too.&amp;nbsp;&lt;code style="background: 0% 0% repeat rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;INSERT INTO tasks&lt;/code&gt;&amp;nbsp;runs locally, the UI updates reactively, and sync happens whenever. Users perceive writes as instantaneous because they are.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Initial sync is where you pay the cost. Bootstrapping the local replica on first load (or on a new device) means downloading potentially megabytes of data. In our app, a workspace with 5,000 tasks, 200 projects, and 50 users takes about 1.2 seconds on broadband and four to five seconds on a slow mobile connection. We mitigate this with partial sync (only sync the user’s active projects) and by showing a one-time “Setting up your workspace” screen during the first sync. After that initial sync, incremental updates are tiny.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Bundle size is a real concern. SQLite compiled to WASM adds roughly 400KB gzipped to your JavaScript bundle. That’s not trivial, especially if you care about Time to Interactive on mobile. I lazy-load the database module with dynamic&amp;nbsp;&lt;code style="background: 0% 0% repeat rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;import()&lt;/code&gt;&amp;nbsp;so it doesn’t block the initial render.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Memory is the other gotcha. SQLite WASM runs in memory, and on mobile browsers with aggressive memory limits, a large database can cause tab crashes. I haven’t found a great solution for this beyond keeping the synced dataset small through partial sync and being aggressive about pruning old data.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Note&lt;/span&gt;: Speaking of memory issues, I’ve been reading&amp;nbsp;&lt;a href="https://www.oreilly.com/library/view/designing-data-intensive-applications/9781491903063/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;&lt;em style="box-sizing: border-box;"&gt;Designing Data-Intensive Applications&lt;/em&gt;&lt;/a&gt;&amp;nbsp;by Martin Kleppmann for the third time. Every re-read, I catch something new. If you haven’t read it and you’re thinking about distributed data, just stop and read it first.&lt;/p&gt;&lt;h2 id="testing-this-stuff" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Testing This Stuff&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/architecture-local-first-web-development/#testing-this-stuff" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;I’ll keep this brief because the honest answer is that testing local-first apps is harder than testing traditional apps, and the tooling isn’t great yet.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;What works for me: unit tests for merge logic (these are pure functions, easy to test), integration tests that spin up two client instances in memory and verify they converge after concurrent edits, and Playwright E2E tests that use&amp;nbsp;&lt;code style="background: 0% 0% repeat rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;context.setOffline(true)&lt;/code&gt;&amp;nbsp;to simulate offline/online transitions.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;What I haven’t figured out well: reproducing bugs that only happen during conflict resolution with specific timing. When a user reports that a task&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;“lost its description,”&lt;/em&gt;&amp;nbsp;I often can’t reproduce it because I don’t know exactly what sequence of offline edits and sync events led to the conflict. I’ve started logging sync events in more detail (what was sent, what was received, what conflicts were detected, how they were resolved) and shipping those logs to our observability stack. It helps, but it’s not as clean as I’d like.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Property-based testing with something like fast-check is genuinely useful for CRDT logic. Generate random operation sequences, apply them in random orders, and assert convergence. I wish I’d started doing this earlier.&lt;/p&gt;&lt;h2 id="what-i-m-watching-what-worries-me" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;What I’m Watching, What Worries Me&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;I’m excited about where this is going. PGlite (full Postgres in the browser) feels like a glimpse of a future where the client/server data layer distinction just dissolves. You write SQL, it runs everywhere, sync is a runtime concern rather than an architectural decision. We’re not there yet, but you can see it from here.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;I’m also watching the convergence of local-first and AI. Running models locally, keeping data on-device, using cloud AI only with explicit consent, and encrypted data. The privacy implications are compelling, and I think&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;“your data never leaves your device”&lt;/em&gt;&amp;nbsp;will become a real product differentiator as AI eats more of the software experience.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;What worries me is&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;fragmentation&lt;/span&gt;. Every sync engine uses its own protocol. There’s no standard. If ElectricSQL shuts down (it won’t, probably, but&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;if&lt;/em&gt;), migrating to PowerSync isn’t trivial. I abstract my sync layer partly for this reason, but it still makes me nervous.&lt;/p&gt;&lt;blockquote class="pull-quote" style="box-sizing: border-box; color: #222222; font-family: Mija; font-size: 32px; font-weight: 700; grid-column-end: 13; grid-column-start: 3; letter-spacing: -0.75px; margin: 1.4em 0px; padding-left: 2.5em; position: relative;"&gt;&lt;p style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0px; margin-top: 0px; word-break: break-word;"&gt;&lt;a aria-label="Share on Twitter" class="pull-quote__link" href="https://twitter.com/share?text=%0aThe%20web%20has%20standards%20for%20nearly%20everything.%20We%20don%e2%80%99t%20have%20one%20for%20sync,%20and%20I%20don%e2%80%99t%20see%20one%20emerging%20soon.%0a&amp;amp;url=https://smashingmagazine.com%2f2026%2f05%2farchitecture-local-first-web-development%2f" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: block; font-size: 1em; line-height: 42px; padding: 0px; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px;"&gt;The web has standards for nearly everything. We don’t have one for sync, and I don’t see one emerging soon.&lt;/a&gt;&lt;/p&gt;&lt;div class="pull-quote__quotation" style="box-sizing: border-box; left: 0px; position: absolute; top: 5px; width: 2em;"&gt;&lt;div class="pull-quote__bg" style="background: 0% 0% repeat rgb(211, 58, 44); border-radius: 11px; box-sizing: border-box; height: 2em; padding-top: 0.15em; text-align: center; transform-origin: left bottom; transform: scale(1) rotateZ(-11deg); transition: transform 0.3s ease-out; width: 2em;"&gt;&lt;span class="pull-quote__symbol" style="box-sizing: border-box; color: white; display: block; font-size: 2.75em; line-height: 1em; transform: rotate(11deg) translateY(5px) translateX(-4px);"&gt;“&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;I’m also worried about the&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;complexity budget&lt;/span&gt;. Local-first adds real architectural complexity: sync engines, conflict resolution, client-side migrations, partial replication, and auth at the sync boundary. For a team of experienced developers building the right kind of app, that complexity pays for itself many times over. For a team that just needs a CRUD app, it’s a trap.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;I keep coming back to something a developer named Kevin said to me at a local-first meetup in Berlin last year:&lt;/p&gt;&lt;blockquote style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgba(245, 242, 240, 0.89) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-left-color: rgb(230, 228, 225); border-left-style: solid; border-left-width: 11px; border-radius: 11px; box-sizing: border-box; color: #424242; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 1.05em; font-style: italic; grid-column-end: 13; grid-column-start: 3; line-height: 1.65em; margin: 0.3em 0px 1.7em; padding-bottom: 1em; padding-top: 1em; padding: 1em calc(1.5em + 0.5vw);"&gt;“The best architecture is the one your team can debug at 2 AM.”&lt;/blockquote&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;He’s right. If local-first makes your app faster, more reliable, and better for users, and your team understands how the sync works, go for it. If you’re adding it because it sounds cool and you don’t fully understand the failure modes yet, build a prototype first. Learn where it breaks. Then decide.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;I’m building my fourth local-first app right now: a collaborative planning tool for small teams, with offline support and optional E2E encryption. It’s the most ambitious thing I’ve attempted with this architecture. I’ll write about how it goes.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;If you’re starting out, pick one feature in your current app that would benefit from instant local reads and offline writes. Add a local SQLite database. Wire up reactive queries. See how it feels. I think you’ll have the same reaction I did: oh,&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;this&lt;/em&gt;&amp;nbsp;is how it should have always worked.&lt;/p&gt;&lt;h2 id="further-reading" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Further Reading&amp;nbsp;&lt;/h2&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;“&lt;a href="https://www.inkandswitch.com/local-first/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Local-First Software&lt;/a&gt;” (Ink &amp;amp; Switch): This is still the best starting point.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;“&lt;a href="https://www.youtube.com/watch?v=PMVBuMK_pJY" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;CRDTs: The hard parts”&lt;/a&gt;” (Martin Kleppmann, video): Martin’s talks on CRDTs are excellent.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;The&amp;nbsp;&lt;a href="https://localfirstweb.dev/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;localfirstweb.dev&lt;/a&gt;&amp;nbsp;community site: A good directory of tools.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://docs.powersync.com/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;PowerSync Documentation&lt;/a&gt;&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://electric-sql.com/docs" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;ElectricSQL Documentation&lt;/a&gt;&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://docs.yjs.dev/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Yjs Documentation&lt;/a&gt;&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://automerge.org/docs/hello/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Automerge Documentation&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;</description><link>http://honeyvig.blogspot.com/2026/06/the-architecture-of-local-first-web.html</link><author>noreply@blogger.com (H)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-9165069509664255576.post-8944276740072501509</guid><pubDate>Thu, 04 Jun 2026 15:51:41 +0000</pubDate><atom:updated>2026-06-04T08:54:24.530-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">AI</category><category domain="http://www.blogger.com/atom/ns#">Design</category><category domain="http://www.blogger.com/atom/ns#">DesignPattern</category><category domain="http://www.blogger.com/atom/ns#">UX</category><title>How To Make Your Design System AI-Ready</title><description>&lt;p&gt;&lt;span face="Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif" style="background-color: white; caret-color: rgb(102, 102, 102); color: #666666; font-size: 23.342123px; font-style: italic;"&gt;Practical guide on how to reduce drifts, minimize mistakes, maintain context, and improve the quality of AI-generated prototypes.&lt;/span&gt;&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 1.1em; grid-column-end: 13; grid-column-start: 3; line-height: 1.55em; margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;AI-generated prototypes&lt;/span&gt;&amp;nbsp;often don’t deliver consistently decent results because of tiny inconsistencies scattered all across a design system. I’s decisions made but not documented, hard-coded values never cleaned up, or&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;relying too much on AI&lt;/span&gt;&amp;nbsp;making sense of mock-ups or design flows on its own.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Yesterday I stumbled upon a&amp;nbsp;&lt;a href="https://hvpandya.com/llm-design-systems" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;useful practical guide&lt;/a&gt;&amp;nbsp;by Hardik Pandya from Atlassian — on&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;how to reduce drifts&lt;/span&gt;, minimize mistakes, maintain context, and improve the quality of AI-generated prototypes. Let’s see how it works.&lt;/p&gt;&lt;figure class="break-out article__image" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 14; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 774.9375px;"&gt;&lt;a href="https://hvpandya.com/llm-design-systems" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="A diagram comparing traditional with LLM-readable design systems by showing their processes and an example file structure." decoding="async" fetchpriority="low" height="1122" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-make-design-system-ai-ready/1-traditional-llm-readable-design-systems.jpg" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-make-design-system-ai-ready/1-traditional-llm-readable-design-systems.jpg 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/how-make-design-system-ai-ready/1-traditional-llm-readable-design-systems.jpg 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/how-make-design-system-ai-ready/1-traditional-llm-readable-design-systems.jpg 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/how-make-design-system-ai-ready/1-traditional-llm-readable-design-systems.jpg 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/how-make-design-system-ai-ready/1-traditional-llm-readable-design-systems.jpg 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; max-width: 50em; padding: 0.75em 2em 0.75em 0px;"&gt;To get better results, AI needs better guidance that minimizes assumptions and reduces ambiguity. Guide by&amp;nbsp;&lt;a href="https://hvpandya.com/llm-design-systems" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Hardik Pandya&lt;/a&gt;.&amp;nbsp;&lt;/figcaption&gt;&lt;/figure&gt;&lt;h2 id="1-design-decisions-are-infrastructure" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;1. Design Decisions Are Infrastructure&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Unsurprisingly, better AI prototypes&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;come from better data&lt;/span&gt;&amp;nbsp;— but also from better human guidance. We shouldn’t assume that AI knows how to choose the right component and how to design with accessibility in mind. It needs priorities, a clear path on how we make decisions, design principles, examples, do’s and don’ts.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;In fact, we should treat design decisions as&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;infrastructure&lt;/span&gt;. That means that every time we make a decision — not just a design decision, but even a decision on how to actually prioritize our work and how we make decisions around here — it must find a path into the spec file that is then consumed by AI.&lt;/p&gt;&lt;h2 id="2-auditing-figmalint" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;2. Auditing: FigmaLint&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;One of the useful tools to audit the quality of the design system is&amp;nbsp;&lt;a href="https://www.figma.com/community/plugin/1521241390290871981/figmalint" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;FigmaLint&lt;/a&gt;. It’s a useful&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;free Figma plugin&lt;/span&gt;&amp;nbsp;for auditing tokens, states, accessibility, binding tokens, renaming layers, detecting detached instances, missing interactive states and hard-coded values — and preparing the design documentation.&lt;/p&gt;&lt;figure style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 679.765625px;"&gt;&lt;a href="https://www.figma.com/community/plugin/1521241390290871981/figmalint" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="A screenshot showcasing FigmaLint, an AI-powered design system auditing and auto-fix tool within Figma, with various UI screens displaying features like component auditing, interactive states, design token usage, and property recommendations." decoding="async" fetchpriority="low" height="450" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-make-design-system-ai-ready/2-figmalint.jpg" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-make-design-system-ai-ready/2-figmalint.jpg 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/how-make-design-system-ai-ready/2-figmalint.jpg 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/how-make-design-system-ai-ready/2-figmalint.jpg 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/how-make-design-system-ai-ready/2-figmalint.jpg 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/how-make-design-system-ai-ready/2-figmalint.jpg 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; padding: 0.75em 2em 0.75em 0px;"&gt;Neat little helper to streamline auditing:&amp;nbsp;&lt;a href="https://www.figma.com/community/plugin/1521241390290871981/figmalint" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;FigmaLint&lt;/a&gt;.&amp;nbsp;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;If you often have to work with&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;vendors and third parties&lt;/span&gt;&amp;nbsp;who supply you with their design systems and component libraries, that’s a great helper to have by your side — especially if you want to improve the quality of prototypes, AI-generated code, and AI-written documentation.&lt;/p&gt;&lt;h2 id="3-three-layers-spec-files-token-layer-auditing" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;3. Three Layers: Spec Files + Token Layer + Auditing&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;To ensure quality, we establish design principles, guidelines, and rules in the form of “&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;spec files”&lt;/span&gt;. It’s structured Markdown files that include spacing rules, color choices, component usage guidelines, priorities, etc. AI is going to read and reuse that spec file every time it’s going to generate a prototype.&lt;/p&gt;&lt;figure class="break-out article__image" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 14; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 774.9375px;"&gt;&lt;a href="https://hvpandya.com/llm-design-systems" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="An example of a folder that organizes spec files to be AI-friendly." decoding="async" fetchpriority="low" height="791" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-make-design-system-ai-ready/3-spec-files.jpg" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-make-design-system-ai-ready/3-spec-files.jpg 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/how-make-design-system-ai-ready/3-spec-files.jpg 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/how-make-design-system-ai-ready/3-spec-files.jpg 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/how-make-design-system-ai-ready/3-spec-files.jpg 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/how-make-design-system-ai-ready/3-spec-files.jpg 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; max-width: 50em; padding: 0.75em 2em 0.75em 0px;"&gt;An example of a folder that organizes spec files to be AI-friendly.&amp;nbsp;&lt;a href="https://hvpandya.com/llm-design-systems" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Jump to full example&lt;/a&gt;. (&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Because the spec files are text files, it’s much more&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;cost-effective&lt;/span&gt;&amp;nbsp;but also much more accurate, just because we don’t rely on AI recognizing or decoding patterns from mock-ups but get specific guidelines instead. In fact, extending code is often a more effective way than generating code from mock-ups.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;token layer&lt;/span&gt;&amp;nbsp;lists and keeps updated all tokens used throughout the design system. AI always chooses from a closed set of named variables instead of inventing plausible values ad hoc.&lt;/p&gt;&lt;figure class="break-out article__image" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 14; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 774.9375px;"&gt;&lt;a href="https://www.linkedin.com/posts/vitalyfriedman_five-levels-of-context-engineering-how-share-7439202839077335040-KoU2" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="Five levels of context engineering" decoding="async" fetchpriority="low" height="1339" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-make-design-system-ai-ready/4-five-levels-context-engineering.jpg" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-make-design-system-ai-ready/4-five-levels-context-engineering.jpg 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/how-make-design-system-ai-ready/4-five-levels-context-engineering.jpg 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/how-make-design-system-ai-ready/4-five-levels-context-engineering.jpg 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/how-make-design-system-ai-ready/4-five-levels-context-engineering.jpg 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/how-make-design-system-ai-ready/4-five-levels-context-engineering.jpg 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; max-width: 50em; padding: 0.75em 2em 0.75em 0px;"&gt;Context engineering is everything. Five levels of context engineering:&amp;nbsp;&lt;a href="https://www.linkedin.com/posts/vitalyfriedman_five-levels-of-context-engineering-how-share-7439202839077335040-KoU2" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;a practical overview&lt;/a&gt;, by Matthew Alverson, via Addy Osmani. (&lt;a href="https://files.smashing.media/articles/how-make-design-system-ai-ready/4-five-levels-context-engineering.jpg" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;An&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;audit script&lt;/span&gt;&amp;nbsp;catches what AI gets wrong. It scans the prototype and flags every hard-coded value and flags it if necessary. It can be a regular software doing that, with AI waiting for its feedback to come back.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Finally, when a design system&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;ships updates&lt;/span&gt;, a sync routine flags which spec files need updating. The goal is to make sure that AI always reads up-to-date, current specs, not the ones written against an outdated version.&lt;/p&gt;&lt;h2 id="4-examples-of-ai-ready-design-systems" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;4. Examples Of AI-Ready Design Systems&amp;nbsp;&lt;/h2&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://atlassian.design/llms.txt" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Atlassian&lt;/a&gt;&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://carbondesignsystem.com/llms.txt" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Carbon&lt;/a&gt;&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://design.cms.gov/llms.txt" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;CMS Design System&lt;/a&gt;&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://nordhealth.design/ai/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Nordhealth&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 id="wrapping-up" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Wrapping Up&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Ultimately, AI&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;cannot magically resolve&lt;/span&gt;&amp;nbsp;technical debt or design debt without proper guidance. It relies heavily on clear decisions, established priorities, and well-defined principles.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The more&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;deliberate and precise&lt;/span&gt;&amp;nbsp;designers are in guiding AI, the better the overall outcomes will be. This requires not just cleaning up and improving design systems but also maintaining them over time as decisions need to trickle down into Markdown files. We’ll be busy for years to come&lt;/p&gt;&lt;h2 id="useful-resources" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Useful Resources&lt;/h2&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://www.figma.com/community/plugin/1521241390290871981/figmalint" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;FigmaLint&lt;/a&gt;, by TJ Pitre&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://atlassian.design/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Atlassian AI-Ready Design System Example&lt;/a&gt;, by Atlassian&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://carbondesignsystem.com/llms.txt" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Carbon AI-Ready Design System Example&lt;/a&gt;, by IBM&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://design.cms.gov/llms.txt" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;CMS Design System AI-Ready Example&lt;/a&gt;, by Centers for Medicare &amp;amp; Medicaid Services&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://nordhealth.design/ai/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Nordhealth AI-Ready Design System Example&lt;/a&gt;, by Nordhealth&lt;/li&gt;&lt;/ul&gt;</description><link>http://honeyvig.blogspot.com/2026/06/how-to-make-your-design-system-ai-ready.html</link><author>noreply@blogger.com (H)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-9165069509664255576.post-49225984406859227</guid><pubDate>Thu, 04 Jun 2026 14:55:15 +0000</pubDate><atom:updated>2026-06-04T09:16:22.212-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">AI</category><category domain="http://www.blogger.com/atom/ns#">Design</category><category domain="http://www.blogger.com/atom/ns#">UX</category><title>Practical Interface Patterns For AI Transparency (Part 2)</title><description>&lt;div class="c-garfield-summary" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 1.4em; margin-top: 0px;"&gt;&lt;section aria-label="Quick summary" class="article__summary" style="align-self: center; border-bottom-color: rgb(229, 229, 229); border-bottom-style: solid; border-bottom-width: 3px; box-sizing: border-box; color: #666666; font-size: 1.15em; font-style: italic; line-height: 1.55em; margin-bottom: 0.5em; margin-top: 0px; padding-bottom: 1.5em; position: initial;"&gt;Why traditional loading patterns like spinners fail in agentic AI experiences, and how interface patterns that reveal the system’s process, status, and decision-making can improve transparency and build user trust.&lt;/section&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 1.1em; grid-column-end: 13; grid-column-start: 3; line-height: 1.55em; margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;In the&amp;nbsp;first part of this series, we talked about the&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Decision Node Audit&lt;/span&gt;. We mapped out the internal workings of our AI system to pinpoint the exact moments it makes decisions based on probabilities. This told us when the system needs to be transparent with the user. Now, the big question is&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;how&lt;/em&gt;&amp;nbsp;to share that information.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;You’ve got your&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Transparency Matrix&lt;/span&gt;&amp;nbsp;ready. You know which behind-the-scenes API calls need a visible status update. Your engineers are on board with the technical aspects. The next step is designing the visual container for those updates.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;We face a legacy problem. For thirty years, interface designers have relied on a single pattern to handle latency:&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;the spinner&lt;/span&gt;. The spinning wheel, the throbber, the progress bar. These patterns communicate a specific technical reality. They tell the user that the system is retrieving data. The delay is caused by bandwidth or file size.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;AI agents introduce a new kind of wait time. When an agent pauses for twenty seconds, it’s not just downloading something; it’s&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;thinking&lt;/em&gt;. It’s figuring out the best steps, weighing options, and creating the content you asked for.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;If we use a basic spinning icon for this “thinking time,” users get confused and anxious. They watch a looping animation and can’t tell if the system is stalled or crashed. They don’t know if the agent is handling a very complicated task or if it has simply failed.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;To build user trust, we need to turn this waiting time into a&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;moment for reassurance&lt;/span&gt;. Instead of a passive&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;“something is happening,”&lt;/em&gt;&amp;nbsp;we need to communicate an active,&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;“Here is exactly how I am working to solve your problem.”&lt;/em&gt;&lt;/p&gt;&lt;h2 id="writing-clear-status-updates" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Writing Clear Status Updates&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;We often think of transparency as a visual design problem, but it’s really about the&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;words&lt;/span&gt;&amp;nbsp;we use. Simple, clear explanations (the microcopy) are what build trust and separate a reliable AI from one that feels broken.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;We need to retire generic placeholders like&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;Loading&lt;/em&gt;&amp;nbsp;or&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;Working&lt;/em&gt;. These words are remnants of the era of static software. Instead, we must construct our status updates using a specific formula that mirrors the agency of the system. Let’s stop using vague words like “Loading” or “Working.” Those terms belong to the past, when software was simple and static. Instead, we should create status updates that clearly tell the user what the system is&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;actually doing&lt;/em&gt;&amp;nbsp;and make the system’s actions transparent.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Imagine, for the sake of an example, you are deploying agentic AI that will help team members organize their calendars and plan recurring meetings on their behalf, once prompted.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;When an AI displays a message like “Checking availability” for an unknown amount of time, users often feel lost because it doesn’t offer enough information. While they understand the AI is looking at a calendar, they don’t know&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;whose&lt;/em&gt;calendar it is, what other steps are involved (before or after), or if the AI even remembered the people and purpose of the scheduling request. Waiting for the final result can be a tense, uneasy experience, like anticipating a gift that you suspect might be a prank.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Perplexity AI provides a strong example of doing status updates right. Figure 1 below shows that when users ask a question, the interface displays exactly what it is doing in real time. You see a list of activities updating as they are accomplished. Users do not need to guess what is happening as the AI works.&lt;/p&gt;&lt;figure class="break-out article__image" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 14; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 774.9375px;"&gt;&lt;a href="https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/1-perplexity-ai.png" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="Perplexity AI example" decoding="async" fetchpriority="low" height="354" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/1-perplexity-ai.png" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/1-perplexity-ai.png 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/1-perplexity-ai.png 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/1-perplexity-ai.png 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/1-perplexity-ai.png 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/1-perplexity-ai.png 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; max-width: 50em; padding: 0.75em 2em 0.75em 0px;"&gt;Figure 1: Perplexity AI is a good example of showing users the AI’s status, including what terms it is using to search the web. (Image source:&amp;nbsp;&lt;a href="https://www.saasui.design/application/perplexity-ai" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;SaaSUI&lt;/a&gt;)&amp;nbsp;&lt;/figcaption&gt;&lt;/figure&gt;&lt;div class="feature-panel-container" data-audience="non-subscriber" data-remove="true" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 1.4em; margin-top: 2.25em;"&gt;&lt;/div&gt;&lt;h2 id="the-agentic-update-formula" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;The Agentic Update Formula&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;To give people useful status updates, we need to connect what the system is&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;doing&lt;/em&gt;with&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;why&lt;/em&gt;&amp;nbsp;it’s doing it. Keeping with our scheduling agent example, the system should break down that waiting period into at least four clear, separate steps.&lt;/p&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;First, the interface displays&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;Checking your calendar to find open times for a recurring Thursday call with [Name(s)]&lt;/em&gt;.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;Then, it updates to:&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;Cross-checking availability with [Name(s)] calendars&lt;/em&gt;.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;Next, it might display:&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;Syncing [Name(s)] schedules to secure your meeting time on [Data and Time]&lt;/em&gt;.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;Finally, at the conclusion, the agent might state they have successfully completed the task and request the user check their email to confirm the invite that’s been shared with the group having the recurring meeting.&lt;/li&gt;&lt;/ul&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;This communication process grounds the technical process in the user’s actual life.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Making an AI’s progress easy to understand boils down to a three-part structure: a strong&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Action Word&lt;/span&gt;, what the AI is working on (the&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Specific Item&lt;/span&gt;), and any&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Limits&lt;/span&gt;&amp;nbsp;or rules it has to follow.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Think about an AI helping you book a trip. A weak, unhelpful update would just be:&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;Searching for flights…&lt;/em&gt;&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;A much better update uses the formula:&lt;/p&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Action Word:&lt;/span&gt;&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;Scanning&lt;/em&gt;&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Specific Item:&lt;/span&gt;&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;the prices on Lufthansa and United&lt;/em&gt;&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Limits/Rules:&lt;/span&gt;&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;to find anything under $600.&lt;/em&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;This approach clearly shows the user that the AI understood their request and is working within the set boundaries.&lt;/p&gt;&lt;figure class="break-out article__image" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 14; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 774.9375px;"&gt;&lt;a href="https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/2-agentic-ai-status-update.png" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="The Anatomy of an Agentic AI Status Update" decoding="async" fetchpriority="low" height="437" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/2-agentic-ai-status-update.png" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/2-agentic-ai-status-update.png 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/2-agentic-ai-status-update.png 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/2-agentic-ai-status-update.png 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/2-agentic-ai-status-update.png 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/2-agentic-ai-status-update.png 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; max-width: 50em; padding: 0.75em 2em 0.75em 0px;"&gt;Figure 2: The Anatomy of an Agentic AI Status Update. (&lt;a href="https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/2-agentic-ai-status-update.png" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;h2 id="matching-tone-to-the-risk-matrix" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Matching Tone To The Risk Matrix&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Should an AI sound like a person or act like a robot? The right answer depends on the task’s importance, which we can figure out using the&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Impact/Risk Matrix&lt;/span&gt;from our&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Decision Node Audit&lt;/span&gt;.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;For simple, low-risk tasks, a friendly, conversational tone works best. For example, a scheduling assistant can say it’s checking your calendar for the best time. This creates a comfortable, easygoing experience for the user.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;However, high-stakes tasks demand clear, mechanical accuracy. If the AI is managing a big financial transfer or a complicated database migration, users don’t want a playful interface; they want precision. A screen that says&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;“I am thinking hard about your money”&lt;/em&gt;&amp;nbsp;would possibly cause panic. Instead, the interface should use straightforward language like&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;“Verifying account routing numbers.”&lt;/em&gt;&amp;nbsp;By adjusting the AI’s “personality” to match the level of risk, we give users exactly the experience they need in that moment. While the Impact/Risk Matrix provides a necessary starting point, the ultimate determinant of the appropriate AI voice and tone is rigorous&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;user research&lt;/span&gt;.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;It’s impossible for any set of rules to predict the exact words or tone that will build trust or cause stress for every group of users or in every situation. That’s why hands-on research is essential. You need to:&lt;/p&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;&lt;a href="https://medium.com/@alienoghli/the-essential-guide-to-a-b-testing-a84b853c16e0" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Run A/B tests&lt;/a&gt;&lt;/span&gt;&amp;nbsp;on different ways the AI “talks” to people.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;&lt;a href="https://uxplanet.org/usability-testing-the-complete-guide-e162898f68db" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Conduct usability studies&lt;/a&gt;&lt;/span&gt;&amp;nbsp;to see how users react emotionally to the system’s messages.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;&lt;a href="https://ixdf.org/literature/article/how-to-conduct-user-interviews" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Perform interviews&lt;/a&gt;&lt;/span&gt;&amp;nbsp;to truly understand what users expect from an AI in terms of openness.&lt;/li&gt;&lt;/ul&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;This kind of research ensures the AI’s “personality” is comfortable and appropriate for the actual people who will be using the system in their specific context.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;We’ve now covered the&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;“what”&lt;/em&gt;&amp;nbsp;— the critical microcopy, the clear action words, and the necessary limits that make an AI status update honest and informative. But words alone aren’t enough. A perfect sentence hidden in a poor interface is still a failure of transparency.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The next challenge is the&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;“how”&lt;/em&gt;&amp;nbsp;— designing the physical delivery system for that message. You can think of the status update formula as the engine, and the interface pattern as the car. A powerful engine needs a reliable, well-designed chassis to carry it down the road.&lt;/p&gt;&lt;h2 id="interface-patterns-a-library-for-agents" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Interface Patterns: A Library For Agents&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Once we have the right words, we need&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;the right container&lt;/span&gt;. The key is matching the message’s weight to the pattern’s visibility. A tiny background task (like an agent gently tidying up your files) doesn’t need a loud, flashing banner. That message is best delivered subtly. A high-stakes, multi-step process (like moving money) potentially demands a more robust container that forces the user to pay attention.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;By creating a library of these patterns, we ensure the right level of transparency is delivered at the right moment, turning the anxiety of waiting into a moment of informed confidence. Let’s review a few common, critical patterns.&lt;/p&gt;&lt;h3 id="the-living-breadcrumb-ai-working-in-the-background" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;THE LIVING BREADCRUMB: AI WORKING IN THE BACKGROUND&amp;nbsp;&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;For those low-importance tasks that an AI is handling quietly in the background, we need a way to show users it’s working without constantly distracting them. We can call this the living breadcrumb.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Think of an email app where an AI is drafting a reply for you. You don’t want a disruptive pop-up message. Instead, a small, subtle status indicator pulses within the application’s border or menu area.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The solution needs to go beyond a static icon. The living breadcrumb smoothly transitions between different text updates. It might pulse from&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;Reading email&lt;/em&gt;&amp;nbsp;to&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;Drafting reply&lt;/em&gt;&amp;nbsp;to&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;Checking tone&lt;/em&gt;. It’s there if you want to check on its progress, offering a quiet assurance that the task is underway, but it won’t demand your immediate attention.&lt;/p&gt;&lt;figure class="break-out article__image" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 14; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 774.9375px;"&gt;&lt;a href="https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/3-living-breadcrumb.jpg" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="" decoding="async" fetchpriority="low" height="437" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/3-living-breadcrumb.jpg" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/3-living-breadcrumb.jpg 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/3-living-breadcrumb.jpg 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/3-living-breadcrumb.jpg 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/3-living-breadcrumb.jpg 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/3-living-breadcrumb.jpg 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; max-width: 50em; padding: 0.75em 2em 0.75em 0px;"&gt;Figure 3: A subtle, living breadcrumb provides assurance in the background for low-priority tasks, showing the AI is working without demanding constant attention. (&lt;a href="https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/3-living-breadcrumb.jpg" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;h3 id="dynamic-checklists" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;DYNAMIC CHECKLISTS&amp;nbsp;&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;When dealing with critical, high-stakes tasks — like processing a complex financial transaction or migrating a large, intricate dataset — we recommend using a&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Dynamic Checklist&lt;/span&gt;&amp;nbsp;(illustrated in Figure 3).&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;This pattern serves as a powerful anchor for the user, providing clarity and confidence about the&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;process’s progress&lt;/span&gt;. Instead of a simple bar, the Dynamic Checklist lays out every planned step the AI agent will take. It clearly highlights the step that is currently in progress, marks preceding steps as complete, and lists future actions as pending.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;For example:&lt;/p&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Step 1&lt;/span&gt;: Verify Account Balance&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;[Complete]&lt;/span&gt;.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Step 2&lt;/span&gt;: Convert Currency&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;[Processing]&lt;/span&gt;.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Step 3&lt;/span&gt;: Transfer Funds&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;[Pending]&lt;/span&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The Dynamic Checklist offers a significant advantage over a traditional progress bar because it expertly manages unpredictable time. If the currency conversion (Step 2) unexpectedly requires an extra ten seconds, the user won’t feel sudden anxiety or panic. They have full visibility into the system’s exact location, understanding that the delay is occurring during the&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;Converting Currency&lt;/em&gt;&amp;nbsp;step. Because they recognize this is a potentially complex action, they are naturally more patient and trusting of the system’s ongoing work.&lt;/p&gt;&lt;figure class="break-out article__image" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 14; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 774.9375px;"&gt;&lt;a href="https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/4-devin-ai.png" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="Devin.ai example" decoding="async" fetchpriority="low" height="652" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/4-devin-ai.png" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/4-devin-ai.png 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/4-devin-ai.png 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/4-devin-ai.png 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/4-devin-ai.png 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/4-devin-ai.png 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; max-width: 50em; padding: 0.75em 2em 0.75em 0px;"&gt;Figure 4: Devin (AI) shows users a dynamic checklist of the tasks it’s accomplished, as well as what remains to be done. (Image source:&amp;nbsp;&lt;a href="https://docs.devin.ai/get-started/devin-intro" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Devin&lt;/a&gt;) (&lt;a href="https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/4-devin-ai.png" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The pattern itself is a compelling UI idea, but designers must remember that its implementation transforms the task into a full-stack design requirement. Unlike a simple loading flag, the dynamic checklist requires a robust front-end state management system to listen for step-completion events, which are typically triggered by a back-end webhook structure. This ensures the interface is always reflecting the agent’s real-time position in the workflow.&lt;/p&gt;&lt;figure class="break-out article__image" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 14; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 774.9375px;"&gt;&lt;a href="https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/5-dynamic-checklist.jpg" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="A dynamic checklist example" decoding="async" fetchpriority="low" height="437" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/5-dynamic-checklist.jpg" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/5-dynamic-checklist.jpg 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/5-dynamic-checklist.jpg 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/5-dynamic-checklist.jpg 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/5-dynamic-checklist.jpg 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/5-dynamic-checklist.jpg 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; max-width: 50em; padding: 0.75em 2em 0.75em 0px;"&gt;&lt;img alt="Advertise with Smashing Magazine" decoding="async" fetchpriority="low" loading="lazy" srcset="https://www.smashingmagazine.com/images/banners/smashing-friskies-300x250.svg" style="border-style: none; box-sizing: border-box; max-width: 100%; position: relative;" width="325" /&gt;Figure 5: A dynamic checklist is excellent to show transparency in what the AI is doing. It clearly shows the user what steps the AI has already finished, what it’s currently working on, and what it plans to do next.&amp;nbsp;&lt;/figcaption&gt;&lt;/figure&gt;&lt;div aria-hidden="true" class="c-friskies-box partners partners__lead partners__lead-place partners__external" data-amount="1" data-audience="non-subscriber" data-remove="true" data-rendered="true" style="align-self: center; border-radius: 11px; box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 0.9em; grid-column-end: 13; grid-column-start: 3; margin: 3em auto 1em; position: relative; width: 679.765625px;"&gt;&lt;ul style="box-sizing: border-box; list-style: outside; margin: 1em 0px 1.4em; max-width: 100%; padding-left: 0px; text-align: center;"&gt;&lt;a class="partners__native--smashing" href="https://www.smashingmagazine.com/contact/" style="border-radius: 11px; box-shadow: none; box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; transition: box-shadow 0.2s ease-in-out, top 0.1s ease-in-out;"&gt;&lt;picture style="box-sizing: border-box;"&gt;&lt;source media="(max-width: 600px)" srcset="https://www.smashingmagazine.com/images/banners/smashing-friskies-300x250.png" style="box-sizing: border-box;"&gt;&lt;/source&gt;&lt;/picture&gt;&lt;/a&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h3 id="the-thinking-toggle" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;THE THINKING TOGGLE&amp;nbsp;&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Some users with higher information needs or higher needs for transparency may not trust a simple summary; they want to see the system’s raw processing. For this audience, we’ve designed the&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Thinking Toggle&lt;/span&gt;.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;This is a simple progressive disclosure UI control, like a chevron or a “View Logs” button, that lets the user expand a friendly status update into a raw terminal view. It displays the sanitized logic logs of the AI agent, such as:&lt;/p&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;em style="box-sizing: border-box;"&gt;Querying API endpoint /v2/search&lt;/em&gt;;&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;em style="box-sizing: border-box;"&gt;Response received: 200 OK&lt;/em&gt;;&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;em style="box-sizing: border-box;"&gt;Filtering results by relevance score &amp;gt; 0.8&lt;/em&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Many people will never open this view. However, for the user who needs deep transparency, the very presence of this toggle is a signal of trust. It reassures them that the system is not concealing anything.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Keep in mind, with this deep transparency comes a critical technical risk. Even for your most expert audience, you must sanitize and abstract these raw logs before display. This step is non-negotiable to prevent accidentally exposing proprietary business logic, internal data structure names, or security tokens that could be exploited. This process ensures trust is built through honesty, not security vulnerability.&lt;/p&gt;&lt;h3 id="designing-for-partial-success" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;DESIGNING FOR PARTIAL SUCCESS&amp;nbsp;&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;In standard software, things are often black or white. A file either saves or it doesn’t. But with AI agents, things are often grey. An agent might plan most of a trip perfectly, yet struggle to book that one special restaurant.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;We need to design for when the AI is mostly successful.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Standard binary (yes or no) error messages are trust-killers because they suggest the AI failed completely. If an agent does 90% of a task and only misses the last 10%, a big red “Request Failed” banner is misleading.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Instead, the interface should clearly show what worked and what didn’t:&lt;/p&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;em style="box-sizing: border-box;"&gt;Flight booked: UA 492&lt;/em&gt;&amp;nbsp;[Success].&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;em style="box-sizing: border-box;"&gt;Hotel reserved: Marriott Downtown&lt;/em&gt;&amp;nbsp;[Success].&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;em style="box-sizing: border-box;"&gt;Car rental: Hertz&lt;/em&gt;&amp;nbsp;[Failed — No inventory].&lt;/li&gt;&lt;/ul&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;This way, you only have to step in and fix the parts that failed, like booking the car yourself, while keeping all the good work the agent already did.&lt;/p&gt;&lt;figure class="break-out article__image" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 14; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 774.9375px;"&gt;&lt;a href="https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/6-designing-partial-success.jpg" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="" decoding="async" fetchpriority="low" height="437" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/6-designing-partial-success.jpg" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/6-designing-partial-success.jpg 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/6-designing-partial-success.jpg 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/6-designing-partial-success.jpg 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/6-designing-partial-success.jpg 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/6-designing-partial-success.jpg 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; max-width: 50em; padding: 0.75em 2em 0.75em 0px;"&gt;Figure 6: We need to be more granular in defining how much of a task has been completed when designing content for agentic AI experiences.&lt;/figcaption&gt;&lt;/figure&gt;&lt;h3 id="disentangling-the-tool" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;DISENTANGLING THE TOOL&amp;nbsp;&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;When an AI system doesn’t perform as expected, it’s crucial to be absolutely clear about the true reason for the failure. Users often mistakenly blame the AI itself for problems that are actually caused by an external service or tool the AI relies on.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;For example, imagine a virtual assistant tries to look at your schedule, but the connection to the Google Calendar API is down. The error message shouldn’t make the assistant look like it failed to do its job.&lt;/p&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Less helpful:&lt;/span&gt;&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;“I could not check your calendar.”&lt;/em&gt;&amp;nbsp;(This suggests the assistant is incompetent.)&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;More helpful and honest:&lt;/span&gt;&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;“The Google Calendar connection is not responding. I will automatically try again in 30 seconds.”&lt;/em&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The first message is frustrating because it makes the AI look like it failed. The second message, though, is much clearer. It explains that the AI is capable, but a broken tool outside its control is causing the issue. This distinction is really important because it keeps the user from losing faith in the AI, even when things go wrong.&lt;/p&gt;&lt;h3 id="the-audit-trail-trust-after-the-fact" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;THE AUDIT TRAIL: TRUST AFTER THE FACT&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Real-time transparency is fleeting. If a user walks away from their desk while the agent is working, they miss the Dynamic Checklist. They return to a finished screen. If the result looks odd, they have no way to verify the work. This is why every agentic workflow requires a persistent Audit Trail.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;We need to design a&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;Show Work&lt;/em&gt;&amp;nbsp;interaction. On the final result screen, provide a link or history log that allows the user to replay the decision logic.&lt;/p&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;em style="box-sizing: border-box;"&gt;See how this price was calculated&lt;/em&gt;;&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;em style="box-sizing: border-box;"&gt;View search sources&lt;/em&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;This receipt is the ultimate safety net. It allows the user to spot-check the validity of the output. Even if they never click it, the mere presence of the receipt tells the user that the system stands behind its work.&lt;/p&gt;&lt;figure class="break-out article__image" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 14; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 774.9375px;"&gt;&lt;a href="https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/7-audit-trail-design-pattern.jpg" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="The Audit trail design pattern" decoding="async" fetchpriority="low" height="437" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/7-audit-trail-design-pattern.jpg" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/7-audit-trail-design-pattern.jpg 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/7-audit-trail-design-pattern.jpg 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/7-audit-trail-design-pattern.jpg 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/7-audit-trail-design-pattern.jpg 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/7-audit-trail-design-pattern.jpg 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; max-width: 50em; padding: 0.75em 2em 0.75em 0px;"&gt;Figure 7: The Audit trail design pattern provides the needed transparency to show users how an outcome was achieved. (&lt;a href="https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/7-audit-trail-design-pattern.jpg" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;ChatGPT provides an example of how now providing users with an easy way to audit the information AI uses can cause confusion or user frustration. ChatGPT remembers you in the way a file cabinet quietly fills up with notes about everything you’ve ever said, then uses those notes to shape every future conversation without telling you. This is called memory. According to developer&amp;nbsp;&lt;a href="https://simonwillison.net/2025/May/21/chatgpt-new-memory/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Simon Willison&lt;/a&gt;, in April 2025, that memory was getting fed into every new conversation automatically.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The problem with ChatGPT’s memory at that time was that you couldn’t see what it remembers, or when it’s using that information, or how it’s influencing what you get back. There’s no log. No timeline. No plain-language list of&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;“here’s what the AI has decided about you.”&lt;/em&gt;&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The only way to glimpse the dossier was to know a specific prompt trick — essentially asking the model to quote its own hidden instructions back to you. Most users will never discover this. They’ll just notice, as Willison did, that ChatGPT placed a “Half Moon Bay” sign in the background of an image they generated (Figure 8) because it had silently cross-referenced their location from previous conversations. This is the absence of transparency (the ability to audit the memory with ease) disguised as personalization. You need to provide users with both.&lt;/p&gt;&lt;figure style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 679.765625px;"&gt;&lt;a href="https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/8-chatgpt-output.png" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="" decoding="async" fetchpriority="low" height="636" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/8-chatgpt-output.png" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/8-chatgpt-output.png 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/8-chatgpt-output.png 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/8-chatgpt-output.png 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/8-chatgpt-output.png 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/8-chatgpt-output.png 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; padding: 0.75em 2em 0.75em 0px;"&gt;Figure 8: Willison asked ChatGPT to put the dog in a pelican costume, but he did not ask for the “Half Moon Bay” sign. Proving that ChatGPT was tracking information on users without clearly allowing users to access what information was being stored. (Image source:&amp;nbsp;&lt;a href="https://simonwillison.net/2025/May/21/chatgpt-new-memory/" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Simon Willison’s Weblog&lt;/a&gt;) (&lt;a href="https://files.smashing.media/articles/practical-interface-patterns-ai-transparency/8-chatgpt-output.png" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;The Audit Trail pattern&lt;/span&gt;&amp;nbsp;is the ultimate solution to the memory audit problem demonstrated by ChatGPT. It is one of four core design solutions that, together, create a library of options for improving AI transparency.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Here is a quick summary of the key interface patterns discussed in this article, which are designed to transform AI waiting time from a moment of anxiety into an opportunity to build user confidence:&lt;/p&gt;&lt;table class="tablesaw break-out" style="border-collapse: collapse; caret-color: rgb(51, 51, 51); clear: both; color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; font-variant-caps: normal; grid-column-end: 14; grid-column-start: 3; margin-bottom: 1.4em; margin-top: 0px; max-width: fit-content; width: 774.9375px;"&gt;&lt;thead style="box-sizing: border-box;"&gt;&lt;tr style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 4px; box-sizing: border-box;"&gt;&lt;th style="border-color: currentcolor currentcolor rgb(221, 221, 221); border-image: none; border-style: none none solid; border-width: medium medium 4px; box-sizing: border-box; font-family: Mija, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; padding: 0.8em 1em; text-align: left;"&gt;Pattern&lt;/th&gt;&lt;th style="border-color: currentcolor currentcolor rgb(221, 221, 221); border-image: none; border-style: none none solid; border-width: medium medium 4px; box-sizing: border-box; font-family: Mija, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; padding: 0.8em 1em; text-align: left;"&gt;Best Use Case&lt;/th&gt;&lt;th style="border-color: currentcolor currentcolor rgb(221, 221, 221); border-image: none; border-style: none none solid; border-width: medium medium 4px; box-sizing: border-box; font-family: Mija, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; padding: 0.8em 1em; text-align: left;"&gt;The User’s Anxiety&lt;/th&gt;&lt;th style="border-color: currentcolor currentcolor rgb(221, 221, 221); border-image: none; border-style: none none solid; border-width: medium medium 4px; box-sizing: border-box; font-family: Mija, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; padding: 0.8em 1em; text-align: left;"&gt;The Trust Signal&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody style="box-sizing: border-box;"&gt;&lt;tr style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 4px; box-sizing: border-box;"&gt;&lt;td data-label="Pattern" style="border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;The Living Breadcrumb&lt;/td&gt;&lt;td data-label="Best Use Case" style="border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;Low-stakes, background tasks (e.g., drafting emails, sorting files).&lt;/td&gt;&lt;td data-label="The User’s Anxiety" style="border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;Did the system stall or freeze?&lt;/td&gt;&lt;td data-label="The Trust Signal" style="border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;I am active, but I won't disturb you.&lt;/td&gt;&lt;/tr&gt;&lt;tr style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 4px; box-sizing: border-box;"&gt;&lt;td data-label="Pattern" style="background-color: #f7f7f7; border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;The Dynamic Checklist&lt;/td&gt;&lt;td data-label="Best Use Case" style="background-color: #f7f7f7; border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;High-stakes workflows with variable time (e.g., financial transfers, booking travel).&lt;/td&gt;&lt;td data-label="The User’s Anxiety" style="background-color: #f7f7f7; border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;Is it stuck? What step is taking so long?&lt;/td&gt;&lt;td data-label="The Trust Signal" style="background-color: #f7f7f7; border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;I have a plan, and I am currently executing Step 2.&lt;/td&gt;&lt;/tr&gt;&lt;tr style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 4px; box-sizing: border-box;"&gt;&lt;td data-label="Pattern" style="border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;The Thinking Toggle&lt;/td&gt;&lt;td data-label="Best Use Case" style="border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;Expert tools or complex data analysis (e.g., code generation, market research).&lt;/td&gt;&lt;td data-label="The User’s Anxiety" style="border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;Is this hallucinating or using real data?&lt;/td&gt;&lt;td data-label="The Trust Signal" style="border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;I have nothing to hide; here are my raw logs.&lt;/td&gt;&lt;/tr&gt;&lt;tr style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 4px; box-sizing: border-box;"&gt;&lt;td data-label="Pattern" style="background-color: #f7f7f7; border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;The Audit Trail&lt;/td&gt;&lt;td data-label="Best Use Case" style="background-color: #f7f7f7; border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;Post-task review for any outcome (e.g., final reports, completed bookings).&lt;/td&gt;&lt;td data-label="The User’s Anxiety" style="background-color: #f7f7f7; border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;How do I know this result is accurate?&lt;/td&gt;&lt;td data-label="The Trust Signal" style="background-color: #f7f7f7; border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;Here is the receipt of my work for you to verify.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;&lt;em style="box-sizing: border-box;"&gt;Table 1:&lt;/em&gt;&lt;/span&gt;&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;Four design patterns enhancing transparency.&lt;/em&gt;&lt;/p&gt;&lt;div aria-hidden="true" class="c-friskies-box partners partners__lead partners__lead-place partners__external" data-amount="1" data-audience="non-subscriber" data-remove="true" style="align-self: center; border-radius: 11px; box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 0.9em; grid-column-end: 13; grid-column-start: 3; margin: 3em auto 1em; position: relative; width: 679.765625px;"&gt;&lt;/div&gt;&lt;h3 id="the-reality-of-attention-when-users-ignore-the-interface" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;THE REALITY OF ATTENTION: WHEN USERS IGNORE THE INTERFACE&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Even the most perfectly designed checklist or the clearest status message may still go ignored by many users.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;When people are working on tons of tasks, especially professionals, they often tune out the interface. Think of an insurance underwriter creating fifty quotes a day — they’re not watching a progress bar. They click “Generate,” switch tabs to answer an email, and only come back when the task is done.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;My research with these experts shows they judge the system based entirely on the final result. They have a good idea of what the answer&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;should&lt;/em&gt;&amp;nbsp;be. If a salesperson expects a premium between $500 and $600, and the system returns $550, they accept it right away, and trust is established.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;These experts tell me that over time, as the AI continues to provide what they perceive as accurate outputs, usage will increase, and they will save time versus manual quoting. Essentially, the system is now viewed as an efficient accelerator of an otherwise monotonous yet mandatory task.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;But if the system returns $900, the user stops. The output is not aligned with expectations, and that’s a problem they must solve. At that moment, the user switched tabs; they missed the little explanation about the high-risk surcharge that popped up in real-time. They didn’t see the specific rule that was triggered. If that explanation disappeared with the progress bar, the user has no way to understand the difference between expectation and outcome. They certainly won’t run the query again just to watch the animation play out.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;They will run the quote by hand, effectively treating the AI’s output as useless and initiating a complete rework of their effort. This manual recalculation feels like a waste of time, which further erodes their confidence in the tool. Once this happens, the user is not interested in&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;why&lt;/em&gt;&amp;nbsp;the system chose $900; they are focused purely on validating or invalidating the system’s accuracy against their own, trusted methods. This lack of transparency, especially in moments of disagreement, is a primary barrier to adoption and consistent use. The audit trail allows us to provide persistent transparency and is the mechanism that prevents the AI from creating more work.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;We need to keep this in mind, particularly when delivering AI-powered tools meant for enterprise use. If the tool delivers a result that misaligns with expectations, you rarely get a second chance. If the user must spend ten minutes investigating why the AI provided that number, they will stop using the AI.&lt;/p&gt;&lt;h3 id="predictability-reliability-and-understanding-are-the-product" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;PREDICTABILITY, RELIABILITY, AND UNDERSTANDING ARE THE PRODUCT&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;We are not building magic tricks. A magic trick relies on misdirection and hidden mechanics. We are building colleagues.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Think of a good colleague, they keep you in the loop. They let you know what they’re up to, what’s taking their time, and when they hit a snag. That honesty is what helps you trust them.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;We can apply this to AI. By using the practical patterns we discussed: giving specific updates, showing a dynamic checklist, acknowledging partial wins, and keeping an audit trail, we stop seeing AI as a mysterious black box that just needs a nice coat of paint. Instead, we start treating it like a team member we can rely on and manage, which builds trust and a clear understanding.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The main reason for using these interface ideas is to achieve real transparency, going beyond explaining the AI’s complicated inner workings. Here, transparency means showing the user the&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;AI’s process and performance&lt;/span&gt;&amp;nbsp;right when they need to see it. This involves plainly communicating the&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;AI’s current status&lt;/span&gt;, its known&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;limits&lt;/span&gt;, and an easy-to-follow&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;history of its decisions&lt;/span&gt;. This level of openness changes the interaction from just accepting what the AI does to actively working with it. It lets users understand why they got a certain result and how they can best step in or guide the system for the best possible outcome.&lt;/p&gt;&lt;h3 id="references" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;REFERENCES&amp;nbsp;&lt;/h3&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;“&lt;a href="https://medium.com/@alienoghli/the-essential-guide-to-a-b-testing-a84b853c16e0" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;The Essential Guide to A/B Testing&lt;/a&gt;”, Ali E. Noghli&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;“&lt;a href="https://uxplanet.org/usability-testing-the-complete-guide-e162898f68db" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Usability testing: the complete guide&lt;/a&gt;”, Andrew Tipp&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;“&lt;a href="https://ixdf.org/literature/article/how-to-conduct-user-interviews" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;How to Conduct User Interviews&lt;/a&gt;”, IxDF&lt;/li&gt;&lt;/ul&gt;</description><link>http://honeyvig.blogspot.com/2026/06/practical-interface-patterns-for-ai.html</link><author>noreply@blogger.com (H)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-9165069509664255576.post-7685982926362958573</guid><pubDate>Thu, 04 Jun 2026 14:49:11 +0000</pubDate><atom:updated>2026-06-04T07:49:11.844-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Business</category><category domain="http://www.blogger.com/atom/ns#">Design</category><category domain="http://www.blogger.com/atom/ns#">UX</category><title>Ten Data-Backed Truths Of User Experience ROI</title><description>&lt;div class="c-garfield-summary" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 1.4em; margin-top: 0px;"&gt;&lt;section aria-label="Quick summary" class="article__summary" style="align-self: center; border-bottom-color: rgb(229, 229, 229); border-bottom-style: solid; border-bottom-width: 3px; box-sizing: border-box; color: #666666; font-size: 1.15em; font-style: italic; line-height: 1.55em; margin-bottom: 0.5em; margin-top: 0px; padding-bottom: 1.5em; position: initial;"&gt;Every extra second of friction has a measurable business cost. Carrie Webster shares ten data-backed UX facts that link user experience directly to revenue, retention, and long-term growth.&lt;/section&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 1.1em; grid-column-end: 13; grid-column-start: 3; line-height: 1.55em; margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;In the high-stakes economy of today, the cost of a friction-heavy interface is no longer just “lost clicks”, but potentially millions in wasted engineering spend and lost business value. As a veteran UX designer who has helped build digital products since the early mobile-first era, I’ve watched business leaders shift from viewing design as a “cosmetic preference” to recognising that user experience is actually the primary engine of business survival.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;A UX design role is as much about&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;research&lt;/span&gt;&amp;nbsp;and&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;analytics&lt;/span&gt;&amp;nbsp;as it is about pixels, and I believe that hard data is the only tool powerful enough to bridge the gap between design and the boardroom. Facts don’t just advocate for the user; they prove that UX is a&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;non-negotiable requirement&lt;/span&gt;&amp;nbsp;for a healthy bottom line. Even in the rooms where decisions are made, UX is frequently undervalued as a ‘visual’ role. I’ve learned that the most effective way to dismantle this myth is through&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;data&lt;/span&gt;.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The following ten facts represent the current reality of the digital world. These are not just “design tips”; they are the clinical, data-backed pillars for financial growth in a saturated market. Some of these facts are also commonly used by designers as best practices.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;For example, I once led a B2C mobile design project, where I was able to strip 1.2 seconds off the mobile load time by reducing and removing some of the visual assets. The result was an immediate 12% lift in completed transactions, proving that in UX, every tenth of a second is a direct lever for revenue.&lt;/p&gt;&lt;h2 id="1-fixing-issues-in-the-design-phase-is-100-times-cheaper" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;1. Fixing Issues In The Design Phase Is 100 Times Cheaper&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;One of the most compelling financial arguments for UX is the&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;1:100 rule&lt;/span&gt;. Modern studies, such as from the&amp;nbsp;&lt;a href="https://www.researchgate.net/figure/BM-System-Science-Institute-Relative-Cost-of-Fixing-Defects_fig1_255965523" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;IBM Systems Institute&lt;/a&gt;&amp;nbsp;and&amp;nbsp;&lt;a href="https://www.seguetech.com/rising-costs-defects/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Sugue Technologies&lt;/a&gt;, show that fixing an error after a product has been developed and launched can be&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;up to 100 times more expensive&lt;/span&gt;&amp;nbsp;than fixing it during the initial design and prototyping phase.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Think of UX as “engineering insurance.” By the time a developer touches the code, every interaction should have been validated. If you discover a fundamental navigation flaw after launch,&amp;nbsp;&lt;a href="https://www.linkedin.com/pulse/2024-cost-fixing-defects-importance-acceptance-a-j-karikari-a10ef/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;you aren’t just paying for the fix&lt;/a&gt;; you’re paying for technical debt, lost developer time, and the revenue lost while users struggle with a broken flow.&lt;/p&gt;&lt;figure class="break-out article__image" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; grid-column-end: 14; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 774.9375px;"&gt;&lt;a href="https://files.smashing.media/articles/data-backed-truths-user-experience-roi/1-cost-bug-fixing.png" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; font-size: 20.297499px; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="Graph showing the cost of bug fixing during different phases." decoding="async" fetchpriority="low" height="420" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/data-backed-truths-user-experience-roi/1-cost-bug-fixing.png" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/data-backed-truths-user-experience-roi/1-cost-bug-fixing.png 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/data-backed-truths-user-experience-roi/1-cost-bug-fixing.png 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/data-backed-truths-user-experience-roi/1-cost-bug-fixing.png 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/data-backed-truths-user-experience-roi/1-cost-bug-fixing.png 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/data-backed-truths-user-experience-roi/1-cost-bug-fixing.png 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; display: table; font-style: italic; margin: 0px auto; max-width: 50em; padding: 0.75em 2em 0.75em 0px;"&gt;&lt;span style="color: #666666;"&gt;&lt;span style="font-size: 0.95em;"&gt;Graph showing the cost of bug fixing during different phases. (Image source:&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href="https://qatestlab.medium.com/the-true-cost-of-a-software-bug-f8ee6a08b10b" style="box-sizing: border-box; color: #666666; font-size: 0.95em; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;QATestLab&lt;/a&gt;&lt;span style="color: #666666;"&gt;&lt;span style="font-size: 0.95em;"&gt;)&amp;nbsp;&lt;/span&gt;&lt;span style="font-size: 19.282623px;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: #333333;"&gt;&lt;span style="font-size: calc(1.5rem + 0.25vw); text-transform: capitalize;"&gt;2. Performance Impacts User Experience&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;In the current landscape, performance is the essential foundation of user experience. A beautiful interface is worthless if the user bounces before it renders.&amp;nbsp;&lt;a href="https://www.wearetenet.com/blog/website-speed-page-load-time-statistics" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;The data is uncompromising&lt;/a&gt;:&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;47% of users expect a page to load in two seconds or less&lt;/span&gt;, and missing this window is a financial catastrophe. A mere one-second delay can reduce conversions by&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;20%&lt;/span&gt;&amp;nbsp;and satisfaction by&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;16%&lt;/span&gt;, while retail businesses lose an estimated&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;$2.6 billion annually&lt;/span&gt;&amp;nbsp;to slow load times. When mobile load time moves from one to three seconds, the bounce rate spikes by&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;32%&lt;/span&gt;, and by the third second, conversion rates typically plummet from&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;40% to 29%&lt;/span&gt;.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;However, this volatility offers a massive lever for growth. Even a microscopic&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;0.1-second improvement&lt;/span&gt;&amp;nbsp;can lift retail conversions by&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;8.4%&lt;/span&gt;, and travel site conversions by&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;10.1%&lt;/span&gt;. Improving your Largest Contentful Paint (LCP) by 31% — a benchmark 67% of websites achieved as of June 2025 — can drive a direct&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;8% increase in sales&lt;/span&gt;. As a long-time designer, I treat speed as a primary design element.&lt;/p&gt;&lt;blockquote style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgba(245, 242, 240, 0.89) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-left-color: rgb(230, 228, 225); border-left-style: solid; border-left-width: 11px; border-radius: 11px; box-sizing: border-box; color: #424242; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 1.05em; font-style: italic; grid-column-end: 13; grid-column-start: 3; line-height: 1.65em; margin: 0.3em 0px 1.7em; padding: 1em calc(1.5em + 0.5vw);"&gt;If the site isn’t instantaneous, the design hasn’t just failed — it effectively doesn’t exist.&lt;/blockquote&gt;&lt;figure class="break-out article__image" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 14; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 774.9375px;"&gt;&lt;a href="https://files.smashing.media/articles/data-backed-truths-user-experience-roi/2-conversion-rate-page-load-time.png" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="Graph showing conversion rate by page load time" decoding="async" fetchpriority="low" height="467" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/data-backed-truths-user-experience-roi/2-conversion-rate-page-load-time.png" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/data-backed-truths-user-experience-roi/2-conversion-rate-page-load-time.png 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/data-backed-truths-user-experience-roi/2-conversion-rate-page-load-time.png 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/data-backed-truths-user-experience-roi/2-conversion-rate-page-load-time.png 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/data-backed-truths-user-experience-roi/2-conversion-rate-page-load-time.png 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/data-backed-truths-user-experience-roi/2-conversion-rate-page-load-time.png 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; max-width: 50em; padding: 0.75em 2em 0.75em 0px;"&gt;When pages load in one second, conversion rates are about 40%. (Image source:&amp;nbsp;&lt;a href="https://www.wearetenet.com/blog/website-speed-page-load-time-statistics" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Tenet&lt;/a&gt;) (&lt;a href="https://files.smashing.media/articles/data-backed-truths-user-experience-roi/2-conversion-rate-page-load-time.png" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;h2 id="3-your-site-has-50-milliseconds-to-impress-your-customers" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;3. Your Site Has 50 Milliseconds To Impress Your Customers&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;First impressions are both&amp;nbsp;&lt;a href="https://www.nngroup.com/articles/first-impressions-human-automaticity/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;visceral and aesthetic&lt;/a&gt;.&amp;nbsp;&lt;a href="https://cxl.com/blog/first-impressions-matter-the-importance-of-great-visual-design/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Research&lt;/a&gt;&amp;nbsp;indicates that users form an opinion about a website’s visual appeal in approximately&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;50 milliseconds&lt;/span&gt;&amp;nbsp;(0.05 seconds). That’s not a lot of time! This split-second “gut-feeling” is a survival mechanism that dictates whether a user stays to explore your value proposition or bounces immediately.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;In the current market,&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;94% of first impressions&lt;/span&gt;&amp;nbsp;are&amp;nbsp;&lt;a href="https://cxl.com/blog/first-impressions-matter-the-importance-of-great-visual-design/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;strictly design related&lt;/a&gt;. If your interface feels “off” or dated, users subconsciously project that lack of quality onto your entire product or service. Your content effectively doesn’t exist if your design hasn’t earned the five seconds of attention required to read it.&lt;/p&gt;&lt;h2 id="4-hick-s-law-the-cost-of-overwhelm" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;4. Hick’s Law: The Cost Of Overwhelm&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Stakeholders often think “more options” equals “more value.” Psychology proves the opposite.&amp;nbsp;&lt;a href="https://ixdf.org/literature/article/hick-s-law-making-the-choice-easier-for-users" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Hick’s Law&lt;/a&gt;&amp;nbsp;states that the time it takes to make a decision increases with the number of options available.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Every extra menu item or form field is a “tax” on the user’s brain. As noted by&amp;nbsp;&lt;a href="https://www.landbase.com/blog/conversion-rate-statistics" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Landbase&lt;/a&gt;, top-performing sites now achieve conversion rates exceeding 11%, while average performers struggle below 3%. Those performing well have applied personalization and optimization strategies to simplify the experience.&lt;/p&gt;&lt;blockquote style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgba(245, 242, 240, 0.89) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-left-color: rgb(230, 228, 225); border-left-style: solid; border-left-width: 11px; border-radius: 11px; box-sizing: border-box; color: #424242; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 1.05em; font-style: italic; grid-column-end: 13; grid-column-start: 3; line-height: 1.65em; margin: 0.3em 0px 1.7em; padding: 1em calc(1.5em + 0.5vw);"&gt;If you want to increase your revenue by tomorrow, find one field to delete from your checkout flow today.&lt;/blockquote&gt;&lt;figure style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 679.765625px;"&gt;&lt;a href="https://files.smashing.media/articles/data-backed-truths-user-experience-roi/3-complex-choices-vs-simple.png" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="Demonstrating complex choices vs simple." decoding="async" fetchpriority="low" height="608" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/data-backed-truths-user-experience-roi/3-complex-choices-vs-simple.png" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/data-backed-truths-user-experience-roi/3-complex-choices-vs-simple.png 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/data-backed-truths-user-experience-roi/3-complex-choices-vs-simple.png 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/data-backed-truths-user-experience-roi/3-complex-choices-vs-simple.png 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/data-backed-truths-user-experience-roi/3-complex-choices-vs-simple.png 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/data-backed-truths-user-experience-roi/3-complex-choices-vs-simple.png 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; padding: 0.75em 2em 0.75em 0px;"&gt;Demonstrating complex choices vs simple. (Image source:&amp;nbsp;&lt;a href="https://ixdf.org/literature/article/hick-s-law-making-the-choice-easier-for-users" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Mads Soegaard&lt;/a&gt;) (&lt;a href="https://files.smashing.media/articles/data-backed-truths-user-experience-roi/3-complex-choices-vs-simple.png" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;h2 id="5-white-space-improves-comprehension" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;5. White Space Improves Comprehension&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/data-backed-truths-user-experience-roi/#5-white-space-improves-comprehension" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;“White space” is often viewed as wasted real estate by non-designers. In reality, it is a tool for focus. Strategic use of white space can&amp;nbsp;&lt;a href="https://www.loop11.com/the-power-of-white-space-in-ux-design/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;increase a user’s content comprehension by up to&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;20%&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;White space prevents “cognitive load” from peaking. By giving the user’s eyes a place to rest, you guide them toward the most important elements, usually your “Buy” or “Sign Up” button. In 2026, as attention spans have dropped to roughly&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;&lt;a href="https://time.com/3858309/attention-spans-goldfish/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;8 seconds&lt;/a&gt;&lt;/span&gt;, simplicity is the ultimate luxury and a major driver of engagement.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;For example, in a fintech dashboard I worked on, analyst users were feeling overwhelmed by a ‘data dump’ layout in some of the dashboard components. I applied more white space around the data to lower their cognitive load. Simply giving the data room to breathe led to a 25% decrease in time-on-task and a significant boost in trial-to-paid conversions.&lt;/p&gt;&lt;h2 id="6-the-power-of-fake-progress" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;6. The Power Of “Fake” Progress&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/data-backed-truths-user-experience-roi/#6-the-power-of-fake-progress" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;One of the most surprising psychological hacks in UX is that users will complete a task faster if they believe they have already made progress. This is known as the&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Goal Gradient Effect&lt;/span&gt;.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;In a classic study, researchers found that a 10-stamp coffee card with two stamps already “pre-filled” was completed significantly faster than an 8-stamp card with zero pre-fills, even though the total spend required was identical. In digital design, showing a progress bar that starts at 15% (simply for creating an account)&amp;nbsp;&lt;a href="https://lawsofux.com/goal-gradient-effect/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;increases completion rates for onboarding by over 40%&lt;/a&gt;. We aren’t just designing screens — we are managing the user’s dopamine and sense of momentum.&lt;/p&gt;&lt;figure class="break-out article__image" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 14; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 774.9375px;"&gt;&lt;a href="https://files.smashing.media/articles/data-backed-truths-user-experience-roi/4-goal-gradient-effect.png" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="Goal Gradient Effect" decoding="async" fetchpriority="low" height="287" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/data-backed-truths-user-experience-roi/4-goal-gradient-effect.png" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/data-backed-truths-user-experience-roi/4-goal-gradient-effect.png 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/data-backed-truths-user-experience-roi/4-goal-gradient-effect.png 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/data-backed-truths-user-experience-roi/4-goal-gradient-effect.png 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/data-backed-truths-user-experience-roi/4-goal-gradient-effect.png 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/data-backed-truths-user-experience-roi/4-goal-gradient-effect.png 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; max-width: 50em; padding: 0.75em 2em 0.75em 0px;"&gt;Increased motivation to reach the target based on current progress. (Image source:&amp;nbsp;&lt;a href="https://conversion-uplift.co.uk/glossary-of-conversion-marketing/goal-gradient-effect/" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Conversion Uplift&lt;/a&gt;) (&lt;a href="https://files.smashing.media/articles/data-backed-truths-user-experience-roi/4-goal-gradient-effect.png" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;h2 id="7-make-your-content-readable" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;7. Make Your Content Readable&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Many stakeholders believe that cramming more text “above the fold” increases value.&amp;nbsp;&lt;a href="https://www.w3.org/WAI/WCAG21/Understanding/visual-presentation.html" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Data proves the opposite&lt;/a&gt;. Proper typography, specifically line spacing (leading) and paragraph width, can increase content comprehension and reading speed by up to&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;20%&lt;/span&gt;.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Optimal line height (generally 1.5x the font size) reduces “visual noise,” allowing the brain to process information with less cognitive effort. When users struggle to read your text due to tight spacing or small fonts, their “perceived effort” increases, leading to a higher bounce rate. Legibility is a conversion tool: if it’s hard to read, it’s hard to buy.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;There are many ways to display more legible text. For example, if line spacing (leading) is too small or the font is too heavy, this also impacts readability.&lt;/p&gt;&lt;figure style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 679.765625px;"&gt;&lt;a href="https://files.smashing.media/articles/data-backed-truths-user-experience-roi/5-difference-readability.png" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="This example demonstrates the difference in readability between a light and a heavy font display." decoding="async" fetchpriority="low" height="618" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/data-backed-truths-user-experience-roi/5-difference-readability.png" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/data-backed-truths-user-experience-roi/5-difference-readability.png 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/data-backed-truths-user-experience-roi/5-difference-readability.png 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/data-backed-truths-user-experience-roi/5-difference-readability.png 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/data-backed-truths-user-experience-roi/5-difference-readability.png 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/data-backed-truths-user-experience-roi/5-difference-readability.png 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; padding: 0.75em 2em 0.75em 0px;"&gt;This example demonstrates the difference in readability between a light and a heavy font display. (Image source:&amp;nbsp;&lt;a href="https://anchordigital.com.au/articles/read-between-the-lines-why-legibility-and-readability-is-essential-for-ux" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Anchor&lt;/a&gt;)&amp;nbsp;&lt;/figcaption&gt;&lt;/figure&gt;&lt;h2 id="8-your-users-only-read-20-of-your-content" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;8. Your Users Only Read 20% Of Your Content&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;This truth meshes well with the previous one. Users do not read your website;&amp;nbsp;&lt;a href="https://www.nngroup.com/articles/how-users-read-on-the-web/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;they scan it&lt;/a&gt;. On a typical web page, users read only about&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;20% to 28% of the text&lt;/span&gt;.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Because modern users scan in an&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;F-pattern&lt;/span&gt;&amp;nbsp;or&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Spotted pattern&lt;/span&gt;, designing for reading is a tactical error. We must design for scanning.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;This requires the following:&lt;/p&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;Bold headers that narrate the value proposition.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;Bullet points for key benefits.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;White space to connect users to key information (discussed in the previous truth).&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;High-contrast call-to-action (CTA) buttons. If your core message is buried in a paragraph, it is invisible to nearly 80% of your audience.&lt;/li&gt;&lt;/ul&gt;&lt;h2 id="9-why-user-testing-with-5-people-is-the-magic-number" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;9. Why User Testing With 5 People Is The Magic Number&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;I have heard of companies that waste six-figure budgets on massive user studies with 100 people, only to get buried in noise. The reality is that testing with just&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;5 users&lt;/span&gt;&amp;nbsp;typically uncovers&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;85% of usability problems&lt;/span&gt;.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;This is a mathematical sweet spot. After the fifth user, you reach the point of diminishing returns — you spend more money to find fewer new bugs. The competitive advantage belongs to small and frequent user testing activities. Test with 5 people, iterate, and test with 5 more. It is the&amp;nbsp;&lt;a href="https://www.nngroup.com/articles/why-you-only-need-to-test-with-5-users/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;most cost-effective way&lt;/a&gt;&amp;nbsp;to build a bulletproof product.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Personally, I have followed this guideline many times during user testing activities, and I can confidently say that testing with 5 people does deliver the majority of issues in your design.&lt;/p&gt;&lt;h2 id="10-the-financial-roi-of-9-900" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;10. The Financial ROI Of 9,900%&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Last, but definitely not least, the most staggering statistic in our industry remains consistent. On average, every&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;$1 invested in UX returns $100&lt;/span&gt;. This 9,900% ROI isn’t magic, but the sum of increased conversion and reduced support.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;A fully optimised UX design can&amp;nbsp;&lt;a href="https://www.forrester.com/report/The-Six-Steps-For-Justifying-Better-UX/RES117708" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;improve conversion rates by up to&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;400%&lt;/span&gt;&lt;/a&gt;. Furthermore, intuitive design significantly lowers customer support requirements. When a product is self-explanatory, you don’t need a massive call centre to explain how to use it.&lt;/p&gt;&lt;h2 id="the-depth-of-ux-investment" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;The Depth Of UX Investment&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/data-backed-truths-user-experience-roi/#the-depth-of-ux-investment" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Beyond these individual statistics, we must address the cumulative effect of a mature UX practice. In my years of practising, the most successful firms are those that treat UX as a continuous improvement loop rather than a one-off project.&amp;nbsp;&lt;a href="https://www.mckinsey.com/business-functions/mckinsey-design/our-insights/the-business-value-of-design" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;The data shows&lt;/a&gt;&amp;nbsp;that companies with high design maturity see&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;32% higher revenue growth&lt;/span&gt;&amp;nbsp;and&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;56% higher total returns to shareholders&lt;/span&gt;compared to their less design-focused peers.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;This discrepancy exists because mature UX organisations move beyond “user delight” and into “user efficiency.” When you shave 30 seconds off a workflow for a team of 1,000 employees, you aren’t just making them happier; you are reclaiming hundreds of thousands of dollars in annual productivity. This internal ROI is often overlooked, but it is just as vital as consumer-facing conversion rates.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Furthermore, the “experience gap” is real.&amp;nbsp;&lt;a href="https://www.bain.com/insights/keeping-up-with-your-customers" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;80% of companies&lt;/a&gt;&amp;nbsp;believe they deliver a “superior experience,” but only 8% of customers agree. This massive disconnect represents a significant market opportunity for those willing to look at the hard data. By bridging this gap through continuous user testing and performance optimisation, you aren’t just improving a product but capturing market share that your competitors are leaving on the table.&lt;/p&gt;&lt;h2 id="the-impact-of-ai" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;The Impact Of AI&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Today, we cannot talk about UX without talking about AI. However, AI hasn’t replaced these 10 facts, but&amp;nbsp;&lt;a href="https://business.adobe.com/au/resources/sdk/the-state-of-customer-experience-in-an-ai-driven-world-b2c.html" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;it has accelerated the solution on some of these&lt;/a&gt;.&lt;/p&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Agentic UX&lt;/span&gt;&lt;br style="box-sizing: border-box;" /&gt;&lt;a href="https://www.databricks.com/resources/ebook/state-of-ai-agents" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;60% of designers are now building “AI agents”&lt;/a&gt;&amp;nbsp;that take actions on behalf of the user, drastically reducing the impact of&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Hick’s Law&lt;/span&gt;&amp;nbsp;by narrowing down choices before the user even sees them.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Real-Time Personalisation&lt;/span&gt;&lt;br style="box-sizing: border-box;" /&gt;32% of teams use AI to personalise interfaces in real-time, meaning the&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;F-Pattern scanning&lt;/span&gt;&amp;nbsp;habits are catered to by moving the most relevant content to exactly where that specific user’s eyes are likely to land.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Automated ROI&lt;/span&gt;&lt;br style="box-sizing: border-box;" /&gt;93% of designers are using generative AI tools to prototype faster, which brings the&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;1:100 Cost Ratio&lt;/span&gt;&amp;nbsp;even lower by allowing us to find and fix errors before a single line of production code is written.&lt;/li&gt;&lt;/ul&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;AI has turned UX from a static map into a living, breathing guide for users. But the fundamental rules of human psychology, such as our 50ms judgments and our need for white space, remain unchanged.&lt;/p&gt;&lt;h2 id="conclusion" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Conclusion&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;In summary, here is a list of the key truths to remember:&lt;/p&gt;&lt;ol style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; counter-reset: listCounter 0; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: none; margin: 0px 0px 1.4em; max-width: 100%; padding: 0px;"&gt;&lt;li style="box-sizing: border-box; counter-increment: listCounter 1; line-height: calc(1.5em + 0.2vw); margin-bottom: 1em; padding-left: calc(1.65em + 0.7vw); position: relative; word-break: break-word;"&gt;Fixing issues in the design phase is 100 times cheaper.&lt;/li&gt;&lt;li style="box-sizing: border-box; counter-increment: listCounter 1; line-height: calc(1.5em + 0.2vw); margin-bottom: 1em; padding-left: calc(1.65em + 0.7vw); position: relative; word-break: break-word;"&gt;Performance impacts user experience.&lt;/li&gt;&lt;li style="box-sizing: border-box; counter-increment: listCounter 1; line-height: calc(1.5em + 0.2vw); margin-bottom: 1em; padding-left: calc(1.65em + 0.7vw); position: relative; word-break: break-word;"&gt;Your site has 50 milliseconds to impress your customers.&lt;/li&gt;&lt;li style="box-sizing: border-box; counter-increment: listCounter 1; line-height: calc(1.5em + 0.2vw); margin-bottom: 1em; padding-left: calc(1.65em + 0.7vw); position: relative; word-break: break-word;"&gt;Hick’s Law: The cost of overwhelm.&lt;/li&gt;&lt;li style="box-sizing: border-box; counter-increment: listCounter 1; line-height: calc(1.5em + 0.2vw); margin-bottom: 1em; padding-left: calc(1.65em + 0.7vw); position: relative; word-break: break-word;"&gt;White space improves comprehension.&lt;/li&gt;&lt;li style="box-sizing: border-box; counter-increment: listCounter 1; line-height: calc(1.5em + 0.2vw); margin-bottom: 1em; padding-left: calc(1.65em + 0.7vw); position: relative; word-break: break-word;"&gt;The power of “fake” progress.&lt;/li&gt;&lt;li style="box-sizing: border-box; counter-increment: listCounter 1; line-height: calc(1.5em + 0.2vw); margin-bottom: 1em; padding-left: calc(1.65em + 0.7vw); position: relative; word-break: break-word;"&gt;Make your content readable.&lt;/li&gt;&lt;li style="box-sizing: border-box; counter-increment: listCounter 1; line-height: calc(1.5em + 0.2vw); margin-bottom: 1em; padding-left: calc(1.65em + 0.7vw); position: relative; word-break: break-word;"&gt;Your users only read 20% of your content.&lt;/li&gt;&lt;li style="box-sizing: border-box; counter-increment: listCounter 1; line-height: calc(1.5em + 0.2vw); margin-bottom: 1em; padding-left: calc(1.65em + 0.7vw); position: relative; word-break: break-word;"&gt;Why user testing with 5 people is the magic number.&lt;/li&gt;&lt;li style="box-sizing: border-box; counter-increment: listCounter 1; line-height: calc(1.5em + 0.2vw); margin-bottom: 1em; padding-left: calc(1.65em + 0.7vw); position: relative; word-break: break-word;"&gt;The financial ROI of 9,900%.&lt;/li&gt;&lt;/ol&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;As we move deeper into the late 2020s, the line between “design” and “business strategy” has vanished. The data is in, and&amp;nbsp;&lt;a href="https://www.mckinsey.com/business-functions/mckinsey-design/our-insights/the-business-value-of-design" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;companies that lead in design outperform their competitors&lt;/a&gt;&amp;nbsp;by&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;1.7x in revenue growth&lt;/span&gt;.&lt;/p&gt;&lt;blockquote class="pull-quote" style="box-sizing: border-box; color: #222222; font-family: Mija; font-size: 32px; font-weight: 700; grid-column-end: 13; grid-column-start: 3; letter-spacing: -0.75px; margin: 1.4em 0px; padding-left: 2.5em; position: relative;"&gt;&lt;p style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0px; margin-top: 0px; word-break: break-word;"&gt;&lt;a aria-label="Share on Twitter" class="pull-quote__link" href="https://twitter.com/share?text=%0aUX%20design%20is%20no%20longer%20a%20team%20you%20hire%20to%20%e2%80%9cmake%20things%20look%20nice.%e2%80%9d%20It%20is%20the%20research-driven,%20data-backed%20discipline%20that%20ensures%20your%20digital%20product%20isn%e2%80%99t%20just%20a%20cost%20centre,%20but%20a%20revenue-generating%20machine.%0a&amp;amp;url=https://smashingmagazine.com%2f2026%2f05%2fdata-backed-truths-user-experience-roi%2f" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: block; font-size: 1em; line-height: 42px; padding: 0px; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px;"&gt;UX design is no longer a team you hire to “make things look nice.” It is the research-driven, data-backed discipline that ensures your digital product isn’t just a cost centre, but a revenue-generating machine.&lt;/a&gt;&lt;/p&gt;&lt;div class="pull-quote__quotation" style="box-sizing: border-box; left: 0px; position: absolute; top: 5px; width: 2em;"&gt;&lt;div class="pull-quote__bg" style="background: rgb(211, 58, 44); border-radius: 11px; box-sizing: border-box; height: 2em; padding-top: 0.15em; text-align: center; transform-origin: left bottom; transform: scale(1) rotateZ(-11deg); transition: transform 0.3s ease-out; width: 2em;"&gt;&lt;span class="pull-quote__symbol" style="box-sizing: border-box; color: white; display: block; font-size: 2.75em; line-height: 1em; transform: rotate(11deg) translateY(5px) translateX(-4px);"&gt;“&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;In fact, this has always been the case, but I hope that in presenting these cold, hard truths, it now becomes a reality for your business.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;As I have found over the years, implementing factual design improvements does make a difference that intuition alone can’t replicate. We are past the era of subjective opinions. The data is clear, the psychology is proven, and the ROI is undeniable. The only question left is whether you’re ready to let the facts lead your design, or if you’ll let your competitors do it first.&lt;/p&gt;</description><link>http://honeyvig.blogspot.com/2026/06/ten-data-backed-truths-of-user.html</link><author>noreply@blogger.com (H)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-9165069509664255576.post-8384691935099390524</guid><pubDate>Thu, 04 Jun 2026 14:43:20 +0000</pubDate><atom:updated>2026-06-04T07:43:20.688-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Design</category><category domain="http://www.blogger.com/atom/ns#">design patterns</category><category domain="http://www.blogger.com/atom/ns#">UX</category><title>Four Levels Of Customer Understanding</title><description>&lt;div class="c-garfield-summary" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 1.4em; margin-top: 0px;"&gt;&lt;section aria-label="Quick summary" class="article__summary" style="align-self: center; border-bottom-color: rgb(229, 229, 229); border-bottom-style: solid; border-bottom-width: 3px; box-sizing: border-box; color: #666666; font-size: 1.15em; font-style: italic; line-height: 1.55em; margin-bottom: 0.5em; margin-top: 0px; padding-bottom: 1.5em; position: initial;"&gt;What people say, feel, think, and do are often very different things. To understand the underlying reasons for user behavior, it helps to look beyond the surface and explore hidden motivations, root causes, and the different layers of reality that shape how people act. Brought to you by&amp;nbsp;&lt;a href="https://measure-ux.com/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Measuring UX Impact&lt;/a&gt;,&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;friendly video course on UX&lt;/span&gt;&amp;nbsp;and design patterns by Vitaly.&lt;/section&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 1.1em; grid-column-end: 13; grid-column-start: 3; line-height: 1.55em; margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Many companies think they know fairly well what their users want and need, and how they make their decisions. Yet most of the time these are merely big assumptions and big hunches — with little real evidence to support them. In practice,&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;obvious reasons&lt;/span&gt;&amp;nbsp;might be true, but they rarely paint the full picture.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;To understand our customers, we must triangulate across&amp;nbsp;&lt;a href="https://www.linkedin.com/posts/hannahshamji_8-months-ago-i-posted-an-original-framework-share-7307469501229420544-t19q/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;four levels of customer understanding&lt;/a&gt;&amp;nbsp;by Hannah Shamji. It’s a useful way to think about the&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;underlying reasons&lt;/span&gt;&amp;nbsp;for user behavior, hidden motivations, and the complex layers of messy and noisy reality that are often overlooked. Let’s see how it works.&lt;/p&gt;&lt;figure style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 679.765625px;"&gt;&lt;a href="https://www.linkedin.com/posts/hannahshamji_8-months-ago-i-posted-an-original-framework-share-7307469501229420544-t19q/" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="A diagram titled Understanding Customers: Four levels of customer understanding, showing four nested pink circles, each representing a level of understanding, with descriptions beside. From outermost to innermost: Level 1 (What they say), Level 2 (What they think or feel), Level 3 (What they do), and Level 4 (Why they do it)." decoding="async" fetchpriority="low" height="706" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/four-levels-customer-understanding/1-four-levels-customer-understanding.jpg" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/four-levels-customer-understanding/1-four-levels-customer-understanding.jpg 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/four-levels-customer-understanding/1-four-levels-customer-understanding.jpg 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/four-levels-customer-understanding/1-four-levels-customer-understanding.jpg 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/four-levels-customer-understanding/1-four-levels-customer-understanding.jpg 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/four-levels-customer-understanding/1-four-levels-customer-understanding.jpg 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; padding: 0.75em 2em 0.75em 0px;"&gt;Four levels of customer understanding: what people say, think or feel, do, and why they do it. By&amp;nbsp;&lt;a href="https://www.linkedin.com/posts/hannahshamji_8-months-ago-i-posted-an-original-framework-share-7307469501229420544-t19q/" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Hannah Shamji&lt;/a&gt;. (&lt;a href="https://files.smashing.media/articles/four-levels-customer-understanding/1-four-levels-customer-understanding.jpg" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;h2 id="don-t-ask-users-your-burning-questions" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Don’t Ask Users Your Burning Questions&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;To learn about customers, it might seem reasonable to&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;ask people&lt;/span&gt;&amp;nbsp;what they think and draw conclusions from it. But it’s&amp;nbsp;&lt;a href="https://www.linkedin.com/pulse/research-questions-interview-erika-hall/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;rarely an effective way&lt;/a&gt;&amp;nbsp;to get actionable answers. In fact, as it turns out, what people&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;think&lt;/em&gt;,&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;feel&lt;/em&gt;,&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;say&lt;/em&gt;, and&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;do&lt;/em&gt;&amp;nbsp;are often&amp;nbsp;&lt;a href="https://uxdesign.cc/dont-ask-users-your-burning-questions-34abedd92a0?sk=v2%2F8aba2177-2a6a-49f9-b9f7-6b173f2b92f8" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;very different things&lt;/a&gt;.&lt;/p&gt;&lt;figure style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 679.765625px;"&gt;&lt;a href="https://www.linkedin.com/feed/update/urn:li:activity:7140680577552117760/" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="A list detailing six reasons people cancel subscriptions, categorized into voluntary and involuntary churn, with explanations for each." decoding="async" fetchpriority="low" height="1001" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/four-levels-customer-understanding/2-reasons-people-cancel-subscriptions.jpeg" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/four-levels-customer-understanding/2-reasons-people-cancel-subscriptions.jpeg 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/four-levels-customer-understanding/2-reasons-people-cancel-subscriptions.jpeg 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/four-levels-customer-understanding/2-reasons-people-cancel-subscriptions.jpeg 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/four-levels-customer-understanding/2-reasons-people-cancel-subscriptions.jpeg 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/four-levels-customer-understanding/2-reasons-people-cancel-subscriptions.jpeg 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; padding: 0.75em 2em 0.75em 0px;"&gt;People don’t always cancel because they want to. Reasons for voluntary and involuntary customer churn. By&amp;nbsp;&lt;a href="https://www.linkedin.com/feed/update/urn:li:activity:7140680577552117760/" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Emily Anderson&lt;/a&gt;. (&lt;a href="https://files.smashing.media/articles/four-levels-customer-understanding/2-reasons-people-cancel-subscriptions.jpeg" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;As Erika Hall&amp;nbsp;&lt;a href="https://medium.com/mule-design/on-surveys-5a73dda5e9a0" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;wrote&lt;/a&gt;, asking a question directly is the&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;worst way&lt;/span&gt;&amp;nbsp;to get a true and useful answer to that question. We don’t always understand or are aware of our&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;true motivations&lt;/span&gt;. We often apply our own context and interpretations to questions.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;We also exaggerate (&lt;em style="box-sizing: border-box;"&gt;a lot!&lt;/em&gt;). We focus on&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;edge cases&lt;/span&gt;&amp;nbsp;and unrealistic scenarios, and we favor&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;short-term goals&lt;/span&gt;&amp;nbsp;over long-term goals. So if users say that they absolutely need to&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;compare products in a table&lt;/em&gt;, it doesn’t mean that they couldn’t get to their underlying goal&amp;nbsp;&lt;a href="https://www.productchart.com/monitors/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;without it&lt;/a&gt;.&lt;/p&gt;&lt;h2 id="possible-vs-probable" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;“Possible” Vs. “Probable”&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Just to indicate how tricky listening to&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;words&lt;/em&gt;&amp;nbsp;alone is: even little&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;nuances in words chosen&lt;/span&gt;&amp;nbsp;matter. In practice, users are rarely precise in expressing their thoughts, and a good example is the distinction between&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;possible&lt;/em&gt;,&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;plausible&lt;/em&gt;, and&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;probable&lt;/em&gt;, as&amp;nbsp;&lt;a href="https://www.linkedin.com/feed/update/urn:li:activity:7447580258918100992/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;discovered by Thomas D’hooge&lt;/a&gt;.&lt;/p&gt;&lt;figure style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 679.765625px;"&gt;&lt;a href="https://www.linkedin.com/feed/update/urn:li:activity:7447580258918100992/" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="A chart showing overlaid density plots (ridge plots) that illustrate the numerical interpretation of various probability phrases" decoding="async" fetchpriority="low" height="1000" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/four-levels-customer-understanding/3-numerical-interpretation-various-probability-phrases.jpeg" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/four-levels-customer-understanding/3-numerical-interpretation-various-probability-phrases.jpeg 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/four-levels-customer-understanding/3-numerical-interpretation-various-probability-phrases.jpeg 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/four-levels-customer-understanding/3-numerical-interpretation-various-probability-phrases.jpeg 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/four-levels-customer-understanding/3-numerical-interpretation-various-probability-phrases.jpeg 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/four-levels-customer-understanding/3-numerical-interpretation-various-probability-phrases.jpeg 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; padding: 0.75em 2em 0.75em 0px;"&gt;Numerical interpretation of probability phrases and their ranges.&amp;nbsp;&lt;a href="https://www.linkedin.com/feed/update/urn:li:activity:7447580258918100992/" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Source&lt;/a&gt;. (&lt;a href="https://files.smashing.media/articles/four-levels-customer-understanding/3-numerical-interpretation-various-probability-phrases.jpeg" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;A&amp;nbsp;&lt;a href="https://jcom.sissa.it/article/pubid/JCOM_1902_2020_A03/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;study on Dutch verbal probability terms&lt;/a&gt;&amp;nbsp;shows how unreliable the choice of words is. While extreme words have some agreement, terms like “possible,” “maybe,” “uncertain,” or “likely” lead to a wide spread of&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;interpretations&lt;/span&gt;. So we shouldn’t rely on what people say, but rather try to go deeper.&lt;/p&gt;&lt;h2 id="the-levels-of-understanding" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;The Levels Of Understanding&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;To get a&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;more realistic and less biased&lt;/span&gt;&amp;nbsp;view of customers’ needs, we need to understand a broader picture across 4 levels:&lt;/p&gt;&lt;figure style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 679.765625px;"&gt;&lt;a href="https://files.smashing.media/articles/four-levels-customer-understanding/4-four-levels-customer-understanding.jpeg" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="A diagram titled Understanding Customers: Four levels of customer understanding, showing four nested pink circles, each representing a level of understanding, with descriptions beside. From outermost to innermost: Level 1 (What they say), Level 2 (What they think or feel), Level 3 (What they do), and Level 4 (Why they do it)." decoding="async" fetchpriority="low" height="800" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/four-levels-customer-understanding/4-four-levels-customer-understanding.jpeg" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/four-levels-customer-understanding/4-four-levels-customer-understanding.jpeg 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/four-levels-customer-understanding/4-four-levels-customer-understanding.jpeg 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/four-levels-customer-understanding/4-four-levels-customer-understanding.jpeg 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/four-levels-customer-understanding/4-four-levels-customer-understanding.jpeg 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/four-levels-customer-understanding/4-four-levels-customer-understanding.jpeg 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; padding: 0.75em 2em 0.75em 0px;"&gt;Four levels of customer understanding: what people say, think or feel, do, and why they do it. By Hannah Shamji, visualized by Helio. (&lt;a href="https://files.smashing.media/articles/four-levels-customer-understanding/4-four-levels-customer-understanding.jpeg" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Level 1: “What they say”&lt;/span&gt;&lt;br style="box-sizing: border-box;" /&gt;Easier to collect, but mostly opinions, and most unreliable. People often explain their behavior through the lens of how they&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;perceive&lt;/em&gt;&amp;nbsp;it, or how they&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;want it to be perceived&lt;/em&gt;, which isn’t always accurate. We shouldn’t rely too much on CRM data, surveys, or polls.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Level 2: “What they think and feel”&lt;/span&gt;&lt;br style="box-sizing: border-box;" /&gt;Gives more context, but is still heavily shaped by memory and personal preferences. Good user research and interviews help us understand expectations and experiences.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Level 3: “What they do”&lt;/span&gt;&lt;br style="box-sizing: border-box;" /&gt;We study actual behavior, actions taken or skipped, usage data, and analytics. We run&amp;nbsp;&lt;a href="https://www.linkedin.com/pulse/breaking-down-complexity-task-analysis-ux-vitaly-friedman-sjt4f/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;task analysis and workflow analysis&lt;/a&gt;&amp;nbsp;to understand how people use the product.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Level 4: “Why they do it”&lt;/span&gt;&lt;br style="box-sizing: border-box;" /&gt;We study&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;underlying motivations&lt;/span&gt;&amp;nbsp;and root causes, through observations of real workflows and in-depth interviews. Typically, it requires a trustworthy relationship with the user, repeat interviews, and task walkthroughs.&lt;/li&gt;&lt;/ul&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Personally, I wouldn’t recommend&amp;nbsp;&lt;a href="https://www.linkedin.com/posts/vitalyfriedman_ux-design-metrics-share-7072585934147371008-XWXu" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;NPS&lt;/a&gt;&amp;nbsp;(&lt;a href="https://www.linkedin.com/posts/vitalyfriedman_measure-ux-in-b2b-an-alternative-to-nps-share-7396872383355256833-eZQQ" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;alternative&lt;/a&gt;). It’s worth noting that different levels might reveal conflicting or contradictory data. To get a better understanding, we need to&amp;nbsp;&lt;a href="https://www.linkedin.com/posts/vitalyfriedman_how-to-resolve-conflicting-data-and-ux-share-7340729861457534979-enqH" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;triangulate and reconcile data&lt;/a&gt;&amp;nbsp;with mixed-method research.&lt;/p&gt;&lt;h2 id="capturing-emotions-and-nuance" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Capturing Emotions And Nuance&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Emotions are always difficult to capture, but they are easier to spot once you observe people doing what they need to do&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;without external influence&lt;/span&gt;&amp;nbsp;or interruptions. The ability to positively impact users grows by moving&amp;nbsp;&lt;a href="https://www.nngroup.com/articles/sympathy-vs-empathy-ux/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;from sympathy to empathy&lt;/a&gt;&amp;nbsp;or even compassion, as articulated by Sarah Gibbons.&lt;/p&gt;&lt;figure style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 679.765625px;"&gt;&lt;a href="https://www.nngroup.com/articles/sympathy-vs-empathy-ux/" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="A diagram titled ‘Spectrum of Empathy’ with a vertical ‘Effort’ axis and a horizontal ‘Understanding &amp;amp; Engagement’ axis. Four overlapping circles, increasing in size from left to right, represent Pity, Sympathy, Empathy, and Compassion, each with a corresponding phrase." decoding="async" fetchpriority="low" height="643" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/four-levels-customer-understanding/5-spectrum-empathy.png" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/four-levels-customer-understanding/5-spectrum-empathy.png 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/four-levels-customer-understanding/5-spectrum-empathy.png 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/four-levels-customer-understanding/5-spectrum-empathy.png 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/four-levels-customer-understanding/5-spectrum-empathy.png 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/four-levels-customer-understanding/5-spectrum-empathy.png 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; padding: 0.75em 2em 0.75em 0px;"&gt;Spectrum of Empathy: from pity to sympathy to empathy to compassion. By&amp;nbsp;&lt;a href="https://www.nngroup.com/articles/sympathy-vs-empathy-ux/" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Sarah Gibbons&lt;/a&gt;. (&lt;a href="https://files.smashing.media/articles/four-levels-customer-understanding/5-spectrum-empathy.png" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;In the past, I was using&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;“speak-aloud” protocol&lt;/em&gt;&amp;nbsp;and asked users to walk me through their thought process as they were completing tasks. But it actually turns out to be quite disruptive. Because people are focused on speaking at the same time while solving a task, many&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;emotions remain hidden&lt;/span&gt;&amp;nbsp;or obscured by their language.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;So, when conducting usability testing,&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;I don’t ask users to speak&lt;/span&gt;&amp;nbsp;through their experience. Instead, I observe where they tap or hover with the mouse, where their mouse circles without an action, where they scroll, and how long. Eventually, when a user confirms that they are done or that they are stuck, I ask questions.&lt;/p&gt;&lt;figure style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 679.765625px;"&gt;&lt;a href="https://uca.edu/bewell/files/2020/11/Feelings-Wheel-Learn-How-to-Label-Your-Feelings.pdf" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="A colorful circular chart of emotions, starting with Happy, Sad, Angry, Fearful, Bad, Surprised, and Disgusted at the inner ring, branching out to more specific feelings in the outer rings." decoding="async" fetchpriority="low" height="800" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/four-levels-customer-understanding/6-circular-chart-emotions.jpeg" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/four-levels-customer-understanding/6-circular-chart-emotions.jpeg 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/four-levels-customer-understanding/6-circular-chart-emotions.jpeg 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/four-levels-customer-understanding/6-circular-chart-emotions.jpeg 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/four-levels-customer-understanding/6-circular-chart-emotions.jpeg 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/four-levels-customer-understanding/6-circular-chart-emotions.jpeg 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; padding: 0.75em 2em 0.75em 0px;"&gt;The Wheel of Emotions helps articulate emotions more precisely. (&lt;a href="https://files.smashing.media/articles/four-levels-customer-understanding/6-circular-chart-emotions.jpeg" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The&amp;nbsp;&lt;a href="https://uca.edu/bewell/files/2020/11/Feelings-Wheel-Learn-How-to-Label-Your-Feelings.pdf" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Emotion Wheel&lt;/a&gt;&amp;nbsp;(&lt;a href="https://feelingswheel.com/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;website&lt;/a&gt;) by Geoffrey Roberts is a helpful little tool for better describing a range of emotions during user interviews or design sessions. It certainly needs refinement for&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;product design needs&lt;/span&gt;, but it helps us get more precise about&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;the sentiment&lt;/span&gt;&amp;nbsp;customers or colleagues might be experiencing, moving beyond just “good” or “bad”.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;One helpful trick is to use&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;mirroring&lt;/span&gt;&amp;nbsp;— repeating what a user has said, or ask the same question twice, just paraphrasing it. Or navigating the emotions wheel (see above) to better capture and understand the emotion.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;These strategies help uncover some of the issues that perhaps didn’t come up in the first answer. That’s also when a user tends to add more useful context and details as they explain their confusion.&lt;/p&gt;&lt;h2 id="emotions-aren-t-everything" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Emotions Aren’t Everything&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Some people&amp;nbsp;&lt;a href="https://alinbuda.com/my-case-against-empathy/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;strongly disagree&lt;/a&gt;:&lt;/p&gt;&lt;blockquote style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgba(245, 242, 240, 0.89) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-left-color: rgb(230, 228, 225); border-left-style: solid; border-left-width: 11px; border-radius: 11px; box-sizing: border-box; color: #424242; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 1.05em; font-style: italic; grid-column-end: 13; grid-column-start: 3; line-height: 1.65em; margin: 0.3em 0px 1.7em; padding: 1em calc(1.5em + 0.5vw);"&gt;“Our work is about others — their problems, their pain, their mess. Our job is to make sense of it and then do something about it. Not to emote or perform but to act on and solve it. There is a&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;flawed belief&lt;/span&gt;&amp;nbsp;that to build great things, you first need to emotionally fully absorb someone else’s experience.”&lt;br style="box-sizing: border-box;" /&gt;&lt;br style="box-sizing: border-box;" /&gt;— Alin Buda&lt;/blockquote&gt;&lt;figure style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 679.765625px;"&gt;&lt;a href="https://www.linkedin.com/posts/indiyoung_uxresearch-designresearch-inclusivedesign-share-7047371089408081920-qEsG/" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="A diagram categorizing potential harms of solutions into mild, serious, lasting, and systemic, with corresponding examples." decoding="async" fetchpriority="low" height="549" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/four-levels-customer-understanding/7-diagram-categorizing-potential-harms-solutions.jpeg" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/four-levels-customer-understanding/7-diagram-categorizing-potential-harms-solutions.jpeg 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/four-levels-customer-understanding/7-diagram-categorizing-potential-harms-solutions.jpeg 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/four-levels-customer-understanding/7-diagram-categorizing-potential-harms-solutions.jpeg 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/four-levels-customer-understanding/7-diagram-categorizing-potential-harms-solutions.jpeg 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/four-levels-customer-understanding/7-diagram-categorizing-potential-harms-solutions.jpeg 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; padding: 0.75em 2em 0.75em 0px;"&gt;Different solutions can cause different levels of harm, which can be way more severe and impactful than emotional response. By&amp;nbsp;&lt;a href="https://www.linkedin.com/posts/indiyoung_uxresearch-designresearch-inclusivedesign-share-7047371089408081920-qEsG/" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Indi Young&lt;/a&gt;. (&lt;a href="https://files.smashing.media/articles/four-levels-customer-understanding/7-diagram-categorizing-potential-harms-solutions.jpeg" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;I think that Alin brings up a very strong argument, and personally, I find it difficult to disagree with. However, I do see user’s emotional response as a&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;signal&lt;/span&gt;of how well the product is working for them. How engaged or detached they are in their journey, how they react to&amp;nbsp;&lt;a href="https://www.chrbutler.com/the-art-secret-behind-all-great-design" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;aesthetics&lt;/a&gt;, how confused or confident they are.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Ultimately, these are signals. To make a difference, we must go&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;beyond emotions&lt;/span&gt;&amp;nbsp;and explore what people actually do. Usually, this means relentlessly observing, diagnosing, and focusing on underlying user needs.&lt;/p&gt;&lt;h2 id="observe-and-diagnose-don-t-validate" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Observe And Diagnose, Don’t Validate&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Instead of asking, we need to&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;observe&lt;/span&gt;. Usually, I focus on small things that make or break an experience. I see where users&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;lose time&lt;/span&gt;, repeat actions, hover without clicking, or click and then go back. Pay attention to subtle cues like scratching their neck, raising eyebrows, or expressions of worry, joy, or confusion.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Many companies talk about “validation” through user testing, but often that means simply confirming existing assumptions. But we should instead&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;diagnose existing behavior&lt;/span&gt;&amp;nbsp;without preconceived notions or affiliations. We don’t validate — we actually research instead.&lt;/p&gt;&lt;figure style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 679.765625px;"&gt;&lt;a href="https://www.linkedin.com/posts/nikkianderson-ux_the-moment-someone-says-lets-validate-this-share-7371206500830199809-nvB0/" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="A diagram categorizing potential harms of solutions into mild, serious, lasting, and systemic, with corresponding examples." decoding="async" fetchpriority="low" height="1002" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/four-levels-customer-understanding/8-words-instead-validate.jpg" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/four-levels-customer-understanding/8-words-instead-validate.jpg 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/four-levels-customer-understanding/8-words-instead-validate.jpg 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/four-levels-customer-understanding/8-words-instead-validate.jpg 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/four-levels-customer-understanding/8-words-instead-validate.jpg 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/four-levels-customer-understanding/8-words-instead-validate.jpg 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; padding: 0.75em 2em 0.75em 0px;"&gt;Words to use instead of “validate”: research, understand, investigate, assess, evaluate, examine, learn. By&amp;nbsp;&lt;a href="https://www.linkedin.com/posts/nikkianderson-ux_the-moment-someone-says-lets-validate-this-share-7371206500830199809-nvB0/" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Nikki Anderson&lt;/a&gt;. (&lt;a href="https://files.smashing.media/articles/four-levels-customer-understanding/8-words-instead-validate.jpg" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;That research means not just understanding&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;customers’ real motivations&lt;/span&gt;, but also risks, doubts, concerns, worries, and perhaps even&amp;nbsp;&lt;a href="https://www.linkedin.com/posts/indiyoung_uxresearch-designresearch-inclusivedesign-share-7047371089408081920-qEsG/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;harms&lt;/a&gt;.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The only way to get there is by building a sincere, honest, and&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;trustworthy relationship&lt;/span&gt;&amp;nbsp;— one that feels right and resonates deeply. When customers truly care and want to help, getting to a real understanding becomes much, much easier.&lt;/p&gt;&lt;h2 id="practical-ways-to-uncover-user-needs" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Practical Ways To Uncover User Needs&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;We don’t need expensive tools to uncover user needs. David Travis provides a&amp;nbsp;&lt;a href="https://medium.com/@userfocus/60-ways-to-understand-user-needs-that-arent-focus-groups-or-surveys-8510e13b3408" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;fantastic overview&lt;/a&gt;&amp;nbsp;of helpful strategies to do just that. Here are some initiatives to spread the word about real user’s struggles or gain a&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;deeper understanding&lt;/span&gt;of user needs:&lt;/p&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Exposure hours&lt;/span&gt;, when every employee must be&amp;nbsp;&lt;a href="https://archive.uie.com/brainsparks/2011/12/19/exposure-hours-drive-ux-innovation/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;exposed to their customers&lt;/a&gt;for at least 2 hours every 6–12 weeks.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Live UX testing&lt;/span&gt;, where we invite everyone in the company to join and observe.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Co-design with users&lt;/span&gt;, where we show new features and ask users to rank them.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Helpdesk insights&lt;/span&gt;, where we ask for frequent complaints and questions from the support every 3–6 months.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Listening in&lt;/span&gt;, where we tune in on a customer service call, web chat, or eavesdrop where users hang out.&lt;/li&gt;&lt;/ul&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The core idea here is that you don’t need extensive and expensive tools to uncover user needs. You need to create spaces where&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;customers’ struggles can be exposed&lt;/span&gt;&amp;nbsp;and make these struggles visible across the entire company.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;It can be&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;short video clips&lt;/span&gt;&amp;nbsp;of user sessions or a monthly newsletter with what we learned this month. Making these pain points visible can rally everyone from marketing to engineering to keep users’ struggles at the back of their minds.&lt;/p&gt;&lt;h2 id="wrapping-up" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Wrapping Up&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;To make an impact, we must go way&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;beyond user feedback&lt;/span&gt;. It’s never enough to listen to surveys — we must&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;observe customers’ actual behaviors&lt;/span&gt;&amp;nbsp;and build relationships to truly understand their goals and their motivations.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;And most importantly, we need to understand&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;what questions&lt;/span&gt;&amp;nbsp;we actually want to have answered. Not what “validation” we need to move on with the project, but what we don’t know and what we need to&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;research&lt;/span&gt;.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Without it, everything else is merely hunches and assumptions — and often wrong and expensive ones.&lt;/p&gt;&lt;h2 id="meet-measure-ux-amp-design-impact" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Meet “Measure UX &amp;amp; Design Impact”&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Meet&amp;nbsp;&lt;a href="https://measure-ux.com/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Measure UX &amp;amp; Design Impact&lt;/span&gt;&lt;/a&gt;, Vitaly’s practical guide&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;for designers and UX leads&lt;/span&gt;&amp;nbsp;on how to track and visualize the incredible&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;impact&lt;/span&gt;&amp;nbsp;of your UX work on business — with a&amp;nbsp;&lt;a href="https://smashingconf.com/online-workshops/workshops/vitaly-friedman-impact-design/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;live UX training&lt;/a&gt;&amp;nbsp;later this year.&amp;nbsp;&lt;a href="https://measure-ux.com/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Jump to details&lt;/a&gt;.&lt;/p&gt;&lt;figure class="break-out" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 14; grid-column-start: 3; margin: 0px auto; padding: 0px; width: 774.9375px;"&gt;&lt;span style="font-size: calc(1.5rem + 0.25vw); text-transform: capitalize;"&gt;Useful Resources&amp;nbsp;&lt;/span&gt;&lt;/figure&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://www.linkedin.com/posts/hannahshamji_8-months-ago-i-posted-an-original-framework-share-7307469501229420544-t19q/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Four Levels of Customer Understanding&lt;/a&gt;, by Hannah Shamji&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://medium.com/@userfocus/60-ways-to-understand-user-needs-that-arent-focus-groups-or-surveys-8510e13b3408" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;60 Ways To Understand User Needs&lt;/a&gt;, by David Travis&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://uca.edu/bewell/files/2020/11/Feelings-Wheel-Learn-How-to-Label-Your-Feelings.pdf" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Emotion Wheel Toolkit (PNG)&lt;/a&gt;, by Geoffrey Roberts&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://uca.edu/bewell/files/2020/11/Feelings-Wheel-Learn-How-to-Label-Your-Feelings.pdf" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Feelings Wheel PDF&lt;/a&gt;&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://feelingswheel.com/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Feelings Wheel Online&lt;/a&gt;&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://alinbuda.com/my-case-against-empathy/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;My Case Against Empathy&lt;/a&gt;, by Alin Buda&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://www.linkedin.com/feed/update/urn:li:activity:7447580258918100992/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Possible vs. Probable&lt;/a&gt;, by Thomas D’hooge&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://jcom.sissa.it/article/pubid/JCOM_1902_2020_A03/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Communicating probability: a multinational study of the interpretation of verbal probability terms&lt;/a&gt;, by Maarten C. de Vries, Marjolijn L. de Boer, and Martine Bouman.&lt;/li&gt;&lt;/ul&gt;&lt;h3 id="useful-books" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;USEFUL BOOKS&amp;nbsp;&lt;/h3&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;em style="box-sizing: border-box;"&gt;Deploy Empathy: A practical guide to interviewing customers&lt;/em&gt;, by Michele Hansen&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;em style="box-sizing: border-box;"&gt;Humankind&lt;/em&gt;, by Rutger Bregman&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;br class="Apple-interchange-newline" /&gt;&lt;/p&gt;</description><link>http://honeyvig.blogspot.com/2026/06/four-levels-of-customer-understanding.html</link><author>noreply@blogger.com (H)</author><thr:total>0</thr:total><enclosure length="421627" type="application/pdf" url="https://uca.edu/bewell/files/2020/11/Feelings-Wheel-Learn-How-to-Label-Your-Feelings.pdf"/><itunes:explicit>no</itunes:explicit><itunes:subtitle>What people say, feel, think, and do are often very different things. To understand the underlying reasons for user behavior, it helps to look beyond the surface and explore hidden motivations, root causes, and the different layers of reality that shape how people act. Brought to you by&amp;nbsp;Measuring UX Impact,&amp;nbsp;friendly video course on UX&amp;nbsp;and design patterns by Vitaly.Many companies think they know fairly well what their users want and need, and how they make their decisions. Yet most of the time these are merely big assumptions and big hunches — with little real evidence to support them. In practice,&amp;nbsp;obvious reasons&amp;nbsp;might be true, but they rarely paint the full picture.To understand our customers, we must triangulate across&amp;nbsp;four levels of customer understanding&amp;nbsp;by Hannah Shamji. It’s a useful way to think about the&amp;nbsp;underlying reasons&amp;nbsp;for user behavior, hidden motivations, and the complex layers of messy and noisy reality that are often overlooked. Let’s see how it works.Four levels of customer understanding: what people say, think or feel, do, and why they do it. By&amp;nbsp;Hannah Shamji. (Large preview)Don’t Ask Users Your Burning Questions&amp;nbsp;To learn about customers, it might seem reasonable to&amp;nbsp;ask people&amp;nbsp;what they think and draw conclusions from it. But it’s&amp;nbsp;rarely an effective way&amp;nbsp;to get actionable answers. In fact, as it turns out, what people&amp;nbsp;think,&amp;nbsp;feel,&amp;nbsp;say, and&amp;nbsp;do&amp;nbsp;are often&amp;nbsp;very different things.People don’t always cancel because they want to. Reasons for voluntary and involuntary customer churn. By&amp;nbsp;Emily Anderson. (Large preview)As Erika Hall&amp;nbsp;wrote, asking a question directly is the&amp;nbsp;worst way&amp;nbsp;to get a true and useful answer to that question. We don’t always understand or are aware of our&amp;nbsp;true motivations. We often apply our own context and interpretations to questions.We also exaggerate (a lot!). We focus on&amp;nbsp;edge cases&amp;nbsp;and unrealistic scenarios, and we favor&amp;nbsp;short-term goals&amp;nbsp;over long-term goals. So if users say that they absolutely need to&amp;nbsp;compare products in a table, it doesn’t mean that they couldn’t get to their underlying goal&amp;nbsp;without it.“Possible” Vs. “Probable”&amp;nbsp;Just to indicate how tricky listening to&amp;nbsp;words&amp;nbsp;alone is: even little&amp;nbsp;nuances in words chosen&amp;nbsp;matter. In practice, users are rarely precise in expressing their thoughts, and a good example is the distinction between&amp;nbsp;possible,&amp;nbsp;plausible, and&amp;nbsp;probable, as&amp;nbsp;discovered by Thomas D’hooge.Numerical interpretation of probability phrases and their ranges.&amp;nbsp;Source. (Large preview)A&amp;nbsp;study on Dutch verbal probability terms&amp;nbsp;shows how unreliable the choice of words is. While extreme words have some agreement, terms like “possible,” “maybe,” “uncertain,” or “likely” lead to a wide spread of&amp;nbsp;interpretations. So we shouldn’t rely on what people say, but rather try to go deeper.The Levels Of Understanding&amp;nbsp;To get a&amp;nbsp;more realistic and less biased&amp;nbsp;view of customers’ needs, we need to understand a broader picture across 4 levels:Four levels of customer understanding: what people say, think or feel, do, and why they do it. By Hannah Shamji, visualized by Helio. (Large preview)Level 1: “What they say”Easier to collect, but mostly opinions, and most unreliable. People often explain their behavior through the lens of how they&amp;nbsp;perceive&amp;nbsp;it, or how they&amp;nbsp;want it to be perceived, which isn’t always accurate. We shouldn’t rely too much on CRM data, surveys, or polls.Level 2: “What they think and feel”Gives more context, but is still heavily shaped by memory and personal preferences. Good user research and interviews help us understand expectations and experiences.Level 3: “What they do”We study actual behavior, actions taken or skipped, usage data, and analytics. We run&amp;nbsp;task analysis and workflow analysis&amp;nbsp;to understand how people use the product.Level 4: “Why they do it”We study&amp;nbsp;underlying motivations&amp;nbsp;and root causes, through observations of real workflows and in-depth interviews. Typically, it requires a trustworthy relationship with the user, repeat interviews, and task walkthroughs.Personally, I wouldn’t recommend&amp;nbsp;NPS&amp;nbsp;(alternative). It’s worth noting that different levels might reveal conflicting or contradictory data. To get a better understanding, we need to&amp;nbsp;triangulate and reconcile data&amp;nbsp;with mixed-method research.Capturing Emotions And Nuance&amp;nbsp;Emotions are always difficult to capture, but they are easier to spot once you observe people doing what they need to do&amp;nbsp;without external influence&amp;nbsp;or interruptions. The ability to positively impact users grows by moving&amp;nbsp;from sympathy to empathy&amp;nbsp;or even compassion, as articulated by Sarah Gibbons.Spectrum of Empathy: from pity to sympathy to empathy to compassion. By&amp;nbsp;Sarah Gibbons. (Large preview)In the past, I was using&amp;nbsp;“speak-aloud” protocol&amp;nbsp;and asked users to walk me through their thought process as they were completing tasks. But it actually turns out to be quite disruptive. Because people are focused on speaking at the same time while solving a task, many&amp;nbsp;emotions remain hidden&amp;nbsp;or obscured by their language.So, when conducting usability testing,&amp;nbsp;I don’t ask users to speak&amp;nbsp;through their experience. Instead, I observe where they tap or hover with the mouse, where their mouse circles without an action, where they scroll, and how long. Eventually, when a user confirms that they are done or that they are stuck, I ask questions.The Wheel of Emotions helps articulate emotions more precisely. (Large preview)The&amp;nbsp;Emotion Wheel&amp;nbsp;(website) by Geoffrey Roberts is a helpful little tool for better describing a range of emotions during user interviews or design sessions. It certainly needs refinement for&amp;nbsp;product design needs, but it helps us get more precise about&amp;nbsp;the sentiment&amp;nbsp;customers or colleagues might be experiencing, moving beyond just “good” or “bad”.One helpful trick is to use&amp;nbsp;mirroring&amp;nbsp;— repeating what a user has said, or ask the same question twice, just paraphrasing it. Or navigating the emotions wheel (see above) to better capture and understand the emotion.These strategies help uncover some of the issues that perhaps didn’t come up in the first answer. That’s also when a user tends to add more useful context and details as they explain their confusion.Emotions Aren’t Everything&amp;nbsp;Some people&amp;nbsp;strongly disagree:“Our work is about others — their problems, their pain, their mess. Our job is to make sense of it and then do something about it. Not to emote or perform but to act on and solve it. There is a&amp;nbsp;flawed belief&amp;nbsp;that to build great things, you first need to emotionally fully absorb someone else’s experience.”— Alin BudaDifferent solutions can cause different levels of harm, which can be way more severe and impactful than emotional response. By&amp;nbsp;Indi Young. (Large preview)I think that Alin brings up a very strong argument, and personally, I find it difficult to disagree with. However, I do see user’s emotional response as a&amp;nbsp;signalof how well the product is working for them. How engaged or detached they are in their journey, how they react to&amp;nbsp;aesthetics, how confused or confident they are.Ultimately, these are signals. To make a difference, we must go&amp;nbsp;beyond emotions&amp;nbsp;and explore what people actually do. Usually, this means relentlessly observing, diagnosing, and focusing on underlying user needs.Observe And Diagnose, Don’t Validate&amp;nbsp;Instead of asking, we need to&amp;nbsp;observe. Usually, I focus on small things that make or break an experience. I see where users&amp;nbsp;lose time, repeat actions, hover without clicking, or click and then go back. Pay attention to subtle cues like scratching their neck, raising eyebrows, or expressions of worry, joy, or confusion.Many companies talk about “validation” through user testing, but often that means simply confirming existing assumptions. But we should instead&amp;nbsp;diagnose existing behavior&amp;nbsp;without preconceived notions or affiliations. We don’t validate — we actually research instead.Words to use instead of “validate”: research, understand, investigate, assess, evaluate, examine, learn. By&amp;nbsp;Nikki Anderson. (Large preview)That research means not just understanding&amp;nbsp;customers’ real motivations, but also risks, doubts, concerns, worries, and perhaps even&amp;nbsp;harms.The only way to get there is by building a sincere, honest, and&amp;nbsp;trustworthy relationship&amp;nbsp;— one that feels right and resonates deeply. When customers truly care and want to help, getting to a real understanding becomes much, much easier.Practical Ways To Uncover User NeedsWe don’t need expensive tools to uncover user needs. David Travis provides a&amp;nbsp;fantastic overview&amp;nbsp;of helpful strategies to do just that. Here are some initiatives to spread the word about real user’s struggles or gain a&amp;nbsp;deeper understandingof user needs:Exposure hours, when every employee must be&amp;nbsp;exposed to their customersfor at least 2 hours every 6–12 weeks.Live UX testing, where we invite everyone in the company to join and observe.Co-design with users, where we show new features and ask users to rank them.Helpdesk insights, where we ask for frequent complaints and questions from the support every 3–6 months.Listening in, where we tune in on a customer service call, web chat, or eavesdrop where users hang out.The core idea here is that you don’t need extensive and expensive tools to uncover user needs. You need to create spaces where&amp;nbsp;customers’ struggles can be exposed&amp;nbsp;and make these struggles visible across the entire company.It can be&amp;nbsp;short video clips&amp;nbsp;of user sessions or a monthly newsletter with what we learned this month. Making these pain points visible can rally everyone from marketing to engineering to keep users’ struggles at the back of their minds.Wrapping Up&amp;nbsp;To make an impact, we must go way&amp;nbsp;beyond user feedback. It’s never enough to listen to surveys — we must&amp;nbsp;observe customers’ actual behaviors&amp;nbsp;and build relationships to truly understand their goals and their motivations.And most importantly, we need to understand&amp;nbsp;what questions&amp;nbsp;we actually want to have answered. Not what “validation” we need to move on with the project, but what we don’t know and what we need to&amp;nbsp;research.Without it, everything else is merely hunches and assumptions — and often wrong and expensive ones.Meet “Measure UX &amp;amp; Design Impact”Meet&amp;nbsp;Measure UX &amp;amp; Design Impact, Vitaly’s practical guide&amp;nbsp;for designers and UX leads&amp;nbsp;on how to track and visualize the incredible&amp;nbsp;impact&amp;nbsp;of your UX work on business — with a&amp;nbsp;live UX training&amp;nbsp;later this year.&amp;nbsp;Jump to details.Useful Resources&amp;nbsp;Four Levels of Customer Understanding, by Hannah Shamji60 Ways To Understand User Needs, by David TravisEmotion Wheel Toolkit (PNG), by Geoffrey RobertsFeelings Wheel PDFFeelings Wheel OnlineMy Case Against Empathy, by Alin BudaPossible vs. Probable, by Thomas D’hoogeCommunicating probability: a multinational study of the interpretation of verbal probability terms, by Maarten C. de Vries, Marjolijn L. de Boer, and Martine Bouman.USEFUL BOOKS&amp;nbsp;Deploy Empathy: A practical guide to interviewing customers, by Michele HansenHumankind, by Rutger Bregman</itunes:subtitle><itunes:author>noreply@blogger.com (H)</itunes:author><itunes:summary>What people say, feel, think, and do are often very different things. To understand the underlying reasons for user behavior, it helps to look beyond the surface and explore hidden motivations, root causes, and the different layers of reality that shape how people act. Brought to you by&amp;nbsp;Measuring UX Impact,&amp;nbsp;friendly video course on UX&amp;nbsp;and design patterns by Vitaly.Many companies think they know fairly well what their users want and need, and how they make their decisions. Yet most of the time these are merely big assumptions and big hunches — with little real evidence to support them. In practice,&amp;nbsp;obvious reasons&amp;nbsp;might be true, but they rarely paint the full picture.To understand our customers, we must triangulate across&amp;nbsp;four levels of customer understanding&amp;nbsp;by Hannah Shamji. It’s a useful way to think about the&amp;nbsp;underlying reasons&amp;nbsp;for user behavior, hidden motivations, and the complex layers of messy and noisy reality that are often overlooked. Let’s see how it works.Four levels of customer understanding: what people say, think or feel, do, and why they do it. By&amp;nbsp;Hannah Shamji. (Large preview)Don’t Ask Users Your Burning Questions&amp;nbsp;To learn about customers, it might seem reasonable to&amp;nbsp;ask people&amp;nbsp;what they think and draw conclusions from it. But it’s&amp;nbsp;rarely an effective way&amp;nbsp;to get actionable answers. In fact, as it turns out, what people&amp;nbsp;think,&amp;nbsp;feel,&amp;nbsp;say, and&amp;nbsp;do&amp;nbsp;are often&amp;nbsp;very different things.People don’t always cancel because they want to. Reasons for voluntary and involuntary customer churn. By&amp;nbsp;Emily Anderson. (Large preview)As Erika Hall&amp;nbsp;wrote, asking a question directly is the&amp;nbsp;worst way&amp;nbsp;to get a true and useful answer to that question. We don’t always understand or are aware of our&amp;nbsp;true motivations. We often apply our own context and interpretations to questions.We also exaggerate (a lot!). We focus on&amp;nbsp;edge cases&amp;nbsp;and unrealistic scenarios, and we favor&amp;nbsp;short-term goals&amp;nbsp;over long-term goals. So if users say that they absolutely need to&amp;nbsp;compare products in a table, it doesn’t mean that they couldn’t get to their underlying goal&amp;nbsp;without it.“Possible” Vs. “Probable”&amp;nbsp;Just to indicate how tricky listening to&amp;nbsp;words&amp;nbsp;alone is: even little&amp;nbsp;nuances in words chosen&amp;nbsp;matter. In practice, users are rarely precise in expressing their thoughts, and a good example is the distinction between&amp;nbsp;possible,&amp;nbsp;plausible, and&amp;nbsp;probable, as&amp;nbsp;discovered by Thomas D’hooge.Numerical interpretation of probability phrases and their ranges.&amp;nbsp;Source. (Large preview)A&amp;nbsp;study on Dutch verbal probability terms&amp;nbsp;shows how unreliable the choice of words is. While extreme words have some agreement, terms like “possible,” “maybe,” “uncertain,” or “likely” lead to a wide spread of&amp;nbsp;interpretations. So we shouldn’t rely on what people say, but rather try to go deeper.The Levels Of Understanding&amp;nbsp;To get a&amp;nbsp;more realistic and less biased&amp;nbsp;view of customers’ needs, we need to understand a broader picture across 4 levels:Four levels of customer understanding: what people say, think or feel, do, and why they do it. By Hannah Shamji, visualized by Helio. (Large preview)Level 1: “What they say”Easier to collect, but mostly opinions, and most unreliable. People often explain their behavior through the lens of how they&amp;nbsp;perceive&amp;nbsp;it, or how they&amp;nbsp;want it to be perceived, which isn’t always accurate. We shouldn’t rely too much on CRM data, surveys, or polls.Level 2: “What they think and feel”Gives more context, but is still heavily shaped by memory and personal preferences. Good user research and interviews help us understand expectations and experiences.Level 3: “What they do”We study actual behavior, actions taken or skipped, usage data, and analytics. We run&amp;nbsp;task analysis and workflow analysis&amp;nbsp;to understand how people use the product.Level 4: “Why they do it”We study&amp;nbsp;underlying motivations&amp;nbsp;and root causes, through observations of real workflows and in-depth interviews. Typically, it requires a trustworthy relationship with the user, repeat interviews, and task walkthroughs.Personally, I wouldn’t recommend&amp;nbsp;NPS&amp;nbsp;(alternative). It’s worth noting that different levels might reveal conflicting or contradictory data. To get a better understanding, we need to&amp;nbsp;triangulate and reconcile data&amp;nbsp;with mixed-method research.Capturing Emotions And Nuance&amp;nbsp;Emotions are always difficult to capture, but they are easier to spot once you observe people doing what they need to do&amp;nbsp;without external influence&amp;nbsp;or interruptions. The ability to positively impact users grows by moving&amp;nbsp;from sympathy to empathy&amp;nbsp;or even compassion, as articulated by Sarah Gibbons.Spectrum of Empathy: from pity to sympathy to empathy to compassion. By&amp;nbsp;Sarah Gibbons. (Large preview)In the past, I was using&amp;nbsp;“speak-aloud” protocol&amp;nbsp;and asked users to walk me through their thought process as they were completing tasks. But it actually turns out to be quite disruptive. Because people are focused on speaking at the same time while solving a task, many&amp;nbsp;emotions remain hidden&amp;nbsp;or obscured by their language.So, when conducting usability testing,&amp;nbsp;I don’t ask users to speak&amp;nbsp;through their experience. Instead, I observe where they tap or hover with the mouse, where their mouse circles without an action, where they scroll, and how long. Eventually, when a user confirms that they are done or that they are stuck, I ask questions.The Wheel of Emotions helps articulate emotions more precisely. (Large preview)The&amp;nbsp;Emotion Wheel&amp;nbsp;(website) by Geoffrey Roberts is a helpful little tool for better describing a range of emotions during user interviews or design sessions. It certainly needs refinement for&amp;nbsp;product design needs, but it helps us get more precise about&amp;nbsp;the sentiment&amp;nbsp;customers or colleagues might be experiencing, moving beyond just “good” or “bad”.One helpful trick is to use&amp;nbsp;mirroring&amp;nbsp;— repeating what a user has said, or ask the same question twice, just paraphrasing it. Or navigating the emotions wheel (see above) to better capture and understand the emotion.These strategies help uncover some of the issues that perhaps didn’t come up in the first answer. That’s also when a user tends to add more useful context and details as they explain their confusion.Emotions Aren’t Everything&amp;nbsp;Some people&amp;nbsp;strongly disagree:“Our work is about others — their problems, their pain, their mess. Our job is to make sense of it and then do something about it. Not to emote or perform but to act on and solve it. There is a&amp;nbsp;flawed belief&amp;nbsp;that to build great things, you first need to emotionally fully absorb someone else’s experience.”— Alin BudaDifferent solutions can cause different levels of harm, which can be way more severe and impactful than emotional response. By&amp;nbsp;Indi Young. (Large preview)I think that Alin brings up a very strong argument, and personally, I find it difficult to disagree with. However, I do see user’s emotional response as a&amp;nbsp;signalof how well the product is working for them. How engaged or detached they are in their journey, how they react to&amp;nbsp;aesthetics, how confused or confident they are.Ultimately, these are signals. To make a difference, we must go&amp;nbsp;beyond emotions&amp;nbsp;and explore what people actually do. Usually, this means relentlessly observing, diagnosing, and focusing on underlying user needs.Observe And Diagnose, Don’t Validate&amp;nbsp;Instead of asking, we need to&amp;nbsp;observe. Usually, I focus on small things that make or break an experience. I see where users&amp;nbsp;lose time, repeat actions, hover without clicking, or click and then go back. Pay attention to subtle cues like scratching their neck, raising eyebrows, or expressions of worry, joy, or confusion.Many companies talk about “validation” through user testing, but often that means simply confirming existing assumptions. But we should instead&amp;nbsp;diagnose existing behavior&amp;nbsp;without preconceived notions or affiliations. We don’t validate — we actually research instead.Words to use instead of “validate”: research, understand, investigate, assess, evaluate, examine, learn. By&amp;nbsp;Nikki Anderson. (Large preview)That research means not just understanding&amp;nbsp;customers’ real motivations, but also risks, doubts, concerns, worries, and perhaps even&amp;nbsp;harms.The only way to get there is by building a sincere, honest, and&amp;nbsp;trustworthy relationship&amp;nbsp;— one that feels right and resonates deeply. When customers truly care and want to help, getting to a real understanding becomes much, much easier.Practical Ways To Uncover User NeedsWe don’t need expensive tools to uncover user needs. David Travis provides a&amp;nbsp;fantastic overview&amp;nbsp;of helpful strategies to do just that. Here are some initiatives to spread the word about real user’s struggles or gain a&amp;nbsp;deeper understandingof user needs:Exposure hours, when every employee must be&amp;nbsp;exposed to their customersfor at least 2 hours every 6–12 weeks.Live UX testing, where we invite everyone in the company to join and observe.Co-design with users, where we show new features and ask users to rank them.Helpdesk insights, where we ask for frequent complaints and questions from the support every 3–6 months.Listening in, where we tune in on a customer service call, web chat, or eavesdrop where users hang out.The core idea here is that you don’t need extensive and expensive tools to uncover user needs. You need to create spaces where&amp;nbsp;customers’ struggles can be exposed&amp;nbsp;and make these struggles visible across the entire company.It can be&amp;nbsp;short video clips&amp;nbsp;of user sessions or a monthly newsletter with what we learned this month. Making these pain points visible can rally everyone from marketing to engineering to keep users’ struggles at the back of their minds.Wrapping Up&amp;nbsp;To make an impact, we must go way&amp;nbsp;beyond user feedback. It’s never enough to listen to surveys — we must&amp;nbsp;observe customers’ actual behaviors&amp;nbsp;and build relationships to truly understand their goals and their motivations.And most importantly, we need to understand&amp;nbsp;what questions&amp;nbsp;we actually want to have answered. Not what “validation” we need to move on with the project, but what we don’t know and what we need to&amp;nbsp;research.Without it, everything else is merely hunches and assumptions — and often wrong and expensive ones.Meet “Measure UX &amp;amp; Design Impact”Meet&amp;nbsp;Measure UX &amp;amp; Design Impact, Vitaly’s practical guide&amp;nbsp;for designers and UX leads&amp;nbsp;on how to track and visualize the incredible&amp;nbsp;impact&amp;nbsp;of your UX work on business — with a&amp;nbsp;live UX training&amp;nbsp;later this year.&amp;nbsp;Jump to details.Useful Resources&amp;nbsp;Four Levels of Customer Understanding, by Hannah Shamji60 Ways To Understand User Needs, by David TravisEmotion Wheel Toolkit (PNG), by Geoffrey RobertsFeelings Wheel PDFFeelings Wheel OnlineMy Case Against Empathy, by Alin BudaPossible vs. Probable, by Thomas D’hoogeCommunicating probability: a multinational study of the interpretation of verbal probability terms, by Maarten C. de Vries, Marjolijn L. de Boer, and Martine Bouman.USEFUL BOOKS&amp;nbsp;Deploy Empathy: A practical guide to interviewing customers, by Michele HansenHumankind, by Rutger Bregman</itunes:summary><itunes:keywords>Design, design patterns, UX</itunes:keywords></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-9165069509664255576.post-8434300935971462882</guid><pubDate>Thu, 04 Jun 2026 14:39:35 +0000</pubDate><atom:updated>2026-06-04T07:39:35.206-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Prototypes</category><category domain="http://www.blogger.com/atom/ns#">User experience</category><category domain="http://www.blogger.com/atom/ns#">User Interface</category><title>Your Prototype Is Not Being Honest With Your Users (And Here’s How To Fix It)</title><description>&lt;div class="c-garfield-summary" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 1.4em; margin-top: 0px;"&gt;&lt;section aria-label="Quick summary" class="article__summary" style="align-self: center; border-bottom-color: rgb(229, 229, 229); border-bottom-style: solid; border-bottom-width: 3px; box-sizing: border-box; color: #666666; font-size: 1.15em; font-style: italic; line-height: 1.55em; margin-bottom: 0.5em; margin-top: 0px; padding-bottom: 1.5em; position: initial;"&gt;There’s a moment in almost every usability session where a participant pauses at the login screen, types something, and glances up: checking whether they’re “doing it right.” That pause is a clear sign. They’ve already clocked that this isn’t a real app, and every data point collected after that moment is filtered through that awareness.&lt;/section&gt;&lt;/div&gt;&lt;div class="sponsor-panel c-felix-the-cat" style="align-items: center; background: rgb(41, 60, 80); border-left: 11px solid var(--feature-panel-bg-color,#1c313a); border-radius: 11px; box-sizing: border-box; color: #e5e5e5; display: flex; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 1.05em; grid-column-end: 13; grid-column-start: 3; justify-content: center; line-height: 1.6em; margin-bottom: 1.4em; margin-left: 0px; margin-top: 0px; padding: 1em 1em 1em 1.5em; text-shadow: none;"&gt;&lt;p class="sponsor-panel-content" style="box-sizing: border-box; flex: 3 1 0%; line-height: calc(1.5em + 0.2vw); word-break: break-word;"&gt;This article has been kindly supported by our dear friends at&amp;nbsp;&lt;a href="https://www.protopie.io/?utm_source=smashingmagazine&amp;amp;utm_medium=referral&amp;amp;utm_campaign=fintech_prototyping_tutorial" style="box-sizing: border-box; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;ProtoPie&lt;/a&gt;&amp;nbsp;who help users turn their ideas into highly interactive animations and prototypes for mobile, desktop, web, and IoT.&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;Thank you!&lt;/em&gt;&lt;/p&gt;&lt;a class="sponsor-panel-image" href="https://www.protopie.io/?utm_source=smashingmagazine&amp;amp;utm_medium=referral&amp;amp;utm_campaign=fintech_prototyping_tutorial" style="background-image: none; box-sizing: border-box; color: #006fc6; display: block; flex: 1 1 0%; margin-left: 1.5em; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;&lt;img alt="ProtoPie" loading="eager" src="https://files.smashing.media/articles/prototype-users-fix-protopie/Vertical%20Logo_White.svg" style="border-style: none; box-sizing: border-box; max-width: 100%; position: relative;" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 1.1em; grid-column-end: 13; grid-column-start: 3; line-height: 1.55em; margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;There’s a moment in almost every usability session where a participant pauses at the login screen, types something, and glances up: checking whether they’re “doing it right.” That pause is a clear sign. They’ve already clocked that this isn’t a real app, and every data point collected after that moment is filtered through that awareness.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;In financial product testing, the problem is sharper. Finance users are trained to notice when something feels off: a balance that doesn’t add up, a field that accepts anything. When a banking prototype skips real authentication, participants don’t just disengage; they stop mid-session to flag it. The team walks away with findings that reflect how users behave in a demonstration, not in a real product.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The fix is narrower than you’d think. Identify the moment where participant trust is established and make that interaction real. In a banking app, that moment is the login.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;This tutorial builds it: credentials that validate, a live error state, and a biometric animation that feels native — no code required.&lt;/p&gt;&lt;h2 id="what-we-re-building-a-login-that-behaves-like-a-shipped-product" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;What We’re Building: A Login That Behaves Like A Shipped Product&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The login flow, built around Pie Bank, a mobile banking prototype, includes functional text inputs, a masked password field, credential validation, a live error state, and a Face ID animation timed to feel indistinguishable from iOS.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;What you’ll need:&lt;/p&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;A login UI from Figma (or any supported design tool)&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://www.protopie.io/download" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;ProtoPie Studio&lt;/a&gt;&amp;nbsp;—&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;free to start&lt;/span&gt;, everything in this tutorial works on the free plan&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;A Lottie file for the Face ID animation (&lt;a href="https://lottiefiles.com/free-animation/face-id-ios-checkmark-ui-animation-SAEU0Y3XHU" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;this one&lt;/a&gt;&amp;nbsp;is what we used)&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;The&amp;nbsp;&lt;a href="https://demo.protopie.cloud/p/606d44ace6d7ea8f41cf38ff" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;finished Pie Bank prototype file&lt;/a&gt;&amp;nbsp;— download it to follow alongside, or use it as a reference after you build&lt;/li&gt;&lt;/ul&gt;&lt;figure style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 679.765625px;"&gt;&lt;img alt="" height="" src="https://files.smashing.media/articles/prototype-users-fix-protopie/Intro_fintech-tutorial-login-usecases-preview.gif" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/figure&gt;&lt;h2 id="step-1-import-from-figma-choose-scene-not-flattened" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Step 1: Import From Figma Choose Scene, Not Flattened&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/prototype-users-fix-protopie/#step-1-import-from-figma-choose-scene-not-flattened" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;In Figma, open the ProtoPie plugin with your login frame selected and choose&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Scene&lt;/span&gt;&amp;nbsp;when exporting. Flattened collapses everything into a single image; Scene preserves your layer hierarchy so every element arrives in ProtoPie as a separate, targetable layer.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Before moving on: rename every layer meaningfully. “Input Username” not “Rectangle 14”. You’ll reference these names in formulas: vague names compound into real time lost.&lt;/p&gt;&lt;figure style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 679.765625px;"&gt;&lt;img alt="" height="" src="https://files.smashing.media/articles/prototype-users-fix-protopie/Step%201_fintech-tutorial-design-import.gif" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/figure&gt;&lt;h2 id="step-2-swap-static-fields-for-inputs-that-actually-accept-text" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Step 2: Swap Static Fields For Inputs That Actually Accept Text&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/prototype-users-fix-protopie/#step-2-swap-static-fields-for-inputs-that-actually-accept-text" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;ProtoPie’s native&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Input&lt;/span&gt;&amp;nbsp;layer accepts real keyboard entry: participants type actual text, not tap a placeholder. Go to&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;Text&lt;/code&gt;&amp;nbsp;&amp;nbsp;→&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;Input&lt;/code&gt;, drag an Input layer onto your canvas, and nest it inside your username field group. Match it visually: placeholder text&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Username&lt;/span&gt;, background fill and font to match your design.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Hit preview. Click the field. Type. That’s the prototype starting to behave like an app rather than depicting one.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Rename this layer&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Input Username&lt;/span&gt;, duplicate it, and nest the copy inside your password field group.&lt;/p&gt;&lt;h2 id="step-3-one-property-change-masks-the-password" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Step 3: One Property Change Masks The Password&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;On the duplicated layer, change placeholder text to&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Password&lt;/span&gt;&amp;nbsp;and set&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Type&lt;/span&gt;&amp;nbsp;to&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Text Password&lt;/span&gt;. ProtoPie handles the masking: no custom logic needed.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Preview both fields: username shows text, password shows dots. It already feels real, and you haven’t written a single condition.&lt;/p&gt;&lt;figure class="break-out article__image" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 14; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 774.9375px;"&gt;&lt;img alt="" decoding="async" fetchpriority="low" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/prototype-users-fix-protopie/Step%203_fintech-tutorial-password.png" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/prototype-users-fix-protopie/Step%203_fintech-tutorial-password.png 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/prototype-users-fix-protopie/Step%203_fintech-tutorial-password.png 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/prototype-users-fix-protopie/Step%203_fintech-tutorial-password.png 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/prototype-users-fix-protopie/Step%203_fintech-tutorial-password.png 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/prototype-users-fix-protopie/Step%203_fintech-tutorial-password.png 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; max-width: 50em; padding: 0.75em 2em 0.75em 0px;"&gt;(Image credit:&amp;nbsp;&lt;a href="" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;&lt;/a&gt;) (&lt;a href="" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;h2 id="step-4-build-the-destination-scene-before-wiring-navigation" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Step 4: Build The Destination Scene Before Wiring Navigation&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/prototype-users-fix-protopie/#step-4-build-the-destination-scene-before-wiring-navigation" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Add a new scene, even a blank one. The most common sequencing mistake in ProtoPie is trying to wire a navigation response before a destination exists. Create it first.&lt;/p&gt;&lt;h2 id="step-5-wire-the-button-it-works-but-it-still-lets-everyone-through" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Step 5: Wire The Button: It Works, But It Still Lets Everyone Through&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Select&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Log In&lt;/span&gt;, add a&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Tap&lt;/span&gt;&amp;nbsp;trigger, set response to&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Jump&lt;/span&gt;, target your dashboard scene, transition&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Slide in from right to left&lt;/span&gt;.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Preview and tap. It navigates: but for any input, including nothing. The prototype is still lying. The next two steps are the fix.&lt;/p&gt;&lt;figure style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 679.765625px;"&gt;&lt;img alt="" height="" src="https://files.smashing.media/articles/prototype-users-fix-protopie/Step%205_fintech-tutorial-login-button.gif" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/figure&gt;&lt;h2 id="step-6-add-variables-so-the-prototype-remembers-what-was-typed" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Step 6: Add Variables So The Prototype Remembers What Was Typed&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;At the bottom-left of ProtoPie, add two&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Text&lt;/span&gt;&amp;nbsp;type variables:&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;username&lt;/code&gt;&amp;nbsp;and&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;password&lt;/code&gt;. Bind each to its input layer with a formula:&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;input&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;"Input Username"&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;text
&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;input&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;"Input Password"&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;text
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Enable the debug icons: green overlays will show live variable values as you type. When you see your keystrokes appear in real time, the binding is confirmed.&lt;/p&gt;&lt;figure class="break-out article__image" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 14; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 774.9375px;"&gt;&lt;img alt="" decoding="async" fetchpriority="low" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/prototype-users-fix-protopie/Step%206_fintech-tutorial_varibales.png" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/prototype-users-fix-protopie/Step%206_fintech-tutorial_varibales.png 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/prototype-users-fix-protopie/Step%206_fintech-tutorial_varibales.png 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/prototype-users-fix-protopie/Step%206_fintech-tutorial_varibales.png 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/prototype-users-fix-protopie/Step%206_fintech-tutorial_varibales.png 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/prototype-users-fix-protopie/Step%206_fintech-tutorial_varibales.png 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; max-width: 50em; padding: 0.75em 2em 0.75em 0px;"&gt;(Image credit:&amp;nbsp;&lt;a href="" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;&lt;/a&gt;) (&lt;a href="" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;h2 id="step-7-add-a-condition-so-only-valid-credentials-get-through" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Step 7: Add A Condition So Only Valid Credentials Get Through&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Go back to the&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Tap&lt;/span&gt;&amp;nbsp;trigger on the login button. Add a&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Condition&lt;/span&gt;&amp;nbsp;with two rules, both must be true:&lt;/p&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;username&lt;/code&gt;&amp;nbsp;equals&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;alex.c@gmail.com&lt;/code&gt;&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;password&lt;/code&gt;&amp;nbsp;equals&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;ABC123&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Move the&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Jump&lt;/span&gt;&amp;nbsp;response inside this condition. Wrong credentials, empty fields, wrong format: none get through. Participants now have to actually log in. That single constraint changes the texture of every test session that follows.&lt;/p&gt;&lt;figure style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 679.765625px;"&gt;&lt;img alt="" height="" src="https://files.smashing.media/articles/prototype-users-fix-protopie/Step%207_fintech-tutorial-condition.gif" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/figure&gt;&lt;h2 id="step-8-build-the-error-state-the-interaction-most-prototypes-skip" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Step 8: Build The Error State, The Interaction Most Prototypes Skip&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Find your error message layer, rename it&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Error Text&lt;/span&gt;, set initial opacity to&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;0&lt;/span&gt;. Add a second condition (the inverse of the first), and inside it, a&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Change Property&lt;/span&gt;response setting&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Error Text&lt;/span&gt;&amp;nbsp;opacity to&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;100&lt;/span&gt;.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Wrong credentials: error appears. Correct credentials: dashboard. Two outcomes: which is what makes this testable, not just demonstrable.&lt;/p&gt;&lt;h2 id="step-9-add-the-face-id-animation-the-detail-that-makes-testers-ask-is-this-real" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Step 9: Add The Face ID Animation, The Detail That Makes Testers Ask “Is This Real”&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Go to&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Media&lt;/span&gt;, drag a&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Lottie&lt;/span&gt;&amp;nbsp;layer onto canvas, load your Face ID file, and position it off-screen above the iPhone frame. On your&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Login with Face ID&lt;/span&gt;&amp;nbsp;button, add a&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Tap&lt;/span&gt;&amp;nbsp;trigger (rename it&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Tap Face ID&lt;/span&gt;) with four responses in sequence:&lt;/p&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Move&lt;/span&gt;: Lottie container to&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;Y: 60&lt;/code&gt;&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Playback&lt;/span&gt;: Seek: time&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;0s&lt;/code&gt;&amp;nbsp;(resets so it always plays from the start)&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Playback: Play&lt;/span&gt;: Lottie file&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Jump&lt;/span&gt;: to dashboard&lt;/li&gt;&lt;/ul&gt;&lt;h2 id="step-10-stagger-the-timing-this-is-what-makes-it-feel-native" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Step 10: Stagger The Timing, This Is What Makes It Feel Native&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Without delays, all four responses fire at once and the scene jumps before the animation plays. Add offsets:&lt;/p&gt;&lt;table class="tablesaw break-out" style="border-collapse: collapse; caret-color: rgb(51, 51, 51); clear: both; color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; font-variant-caps: normal; grid-column-end: 14; grid-column-start: 3; margin-bottom: 1.4em; margin-top: 0px; max-width: fit-content; width: 225.453125px;"&gt;&lt;thead style="box-sizing: border-box;"&gt;&lt;tr style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 4px; box-sizing: border-box;"&gt;&lt;th style="border-color: currentcolor currentcolor rgb(221, 221, 221); border-image: none; border-style: none none solid; border-width: medium medium 4px; box-sizing: border-box; font-family: Mija, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; padding: 0.8em 1em; text-align: left;"&gt;Response&lt;/th&gt;&lt;th style="border-color: currentcolor currentcolor rgb(221, 221, 221); border-image: none; border-style: none none solid; border-width: medium medium 4px; box-sizing: border-box; font-family: Mija, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; padding: 0.8em 1em; text-align: left;"&gt;Delay&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody style="box-sizing: border-box;"&gt;&lt;tr style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 4px; box-sizing: border-box;"&gt;&lt;td data-label="Response" style="border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;Move&lt;/td&gt;&lt;td data-label="Delay" style="border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;0s&lt;/td&gt;&lt;/tr&gt;&lt;tr style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 4px; box-sizing: border-box;"&gt;&lt;td data-label="Response" style="background-color: #f7f7f7; border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;Seek&lt;/td&gt;&lt;td data-label="Delay" style="background-color: #f7f7f7; border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;0s&lt;/td&gt;&lt;/tr&gt;&lt;tr style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 4px; box-sizing: border-box;"&gt;&lt;td data-label="Response" style="border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;Play&lt;/td&gt;&lt;td data-label="Delay" style="border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;0.5s&lt;/td&gt;&lt;/tr&gt;&lt;tr style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 4px; box-sizing: border-box;"&gt;&lt;td data-label="Response" style="background-color: #f7f7f7; border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;Jump&lt;/td&gt;&lt;td data-label="Delay" style="background-color: #f7f7f7; border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;1s&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Enable&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Reset selected scenes&lt;/span&gt;&amp;nbsp;on Jump: without it, navigating back leaves the animation stuck at&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;Y: 60&lt;/code&gt;.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Preview: tap Face ID, animation drops in, plays, screen transitions. A biometric login indistinguishable from the real thing.&lt;/p&gt;&lt;figure style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 679.765625px;"&gt;&lt;img alt="" height="" src="https://files.smashing.media/articles/prototype-users-fix-protopie/Step%2010_fintech-tutorial-faceID.gif" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;figcaption style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; padding: 0.75em 2em 0.75em 0px;"&gt;You can download&amp;nbsp;&lt;a href="https://demo.protopie.cloud/p/606d44ace6d7ea8f41cf38ff" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Pie Bank, Chapter 1: Login Flow&lt;/a&gt;&amp;nbsp;and explore it freely.&lt;/figcaption&gt;&lt;/figure&gt;&lt;h2 id="a-login-this-real-changes-what-you-can-learn-from-your-prototype" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;A Login This Real Changes What You Can Learn From Your Prototype&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;When authentication actually works, the error state becomes a genuine research touchpoint: do users understand the message, do they retry, do they reach for Face ID instead? These are questions a faked login can’t answer.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;In stakeholder reviews, the flow speaks for itself. In engineering handoff, the interaction panel documents the behavior (conditional logic, variable bindings, timing) so engineers see intent, not interpretation.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;This is why FinTech teams invest in login fidelity even when the login isn’t the feature being tested. It’s where participant trust is established. Get it right, and everything downstream produces better signal.&lt;/p&gt;&lt;hr style="background: rgb(211, 58, 44); border-radius: 11px; box-sizing: content-box; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; height: 4px; margin: 0px; overflow: visible;" /&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;em style="box-sizing: border-box;"&gt;This tutorial is part of the&amp;nbsp;&lt;a href="https://www.protopie.io/blog/fintech-prototyping-with-protopie" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;FinTech Prototyping with ProtoPie&lt;/a&gt;&amp;nbsp;series on the ProtoPie blog. The series builds Pie Bank from the ground up across four chapters, covering the dashboard, money transfer logic, and camera integration. If this tutorial was useful, the rest of the series goes further.&lt;/em&gt;&lt;/p&gt;</description><link>http://honeyvig.blogspot.com/2026/06/your-prototype-is-not-being-honest-with.html</link><author>noreply@blogger.com (H)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-9165069509664255576.post-2542890688022621757</guid><pubDate>Thu, 04 Jun 2026 14:37:09 +0000</pubDate><atom:updated>2026-06-04T07:37:09.873-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Coding TEchniques</category><category domain="http://www.blogger.com/atom/ns#">CSS</category><title>Algorithmic Theming Engines: Building Self-Correcting Color Systems With contrast-color()</title><description>&lt;div class="c-garfield-summary" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 1.4em; margin-top: 0px;"&gt;&lt;section aria-label="Quick summary" class="article__summary" style="align-self: center; border-bottom-color: rgb(229, 229, 229); border-bottom-style: solid; border-bottom-width: 3px; box-sizing: border-box; color: #666666; font-size: 1.15em; font-style: italic; line-height: 1.55em; margin-bottom: 0.5em; margin-top: 0px; padding-bottom: 1.5em; position: initial;"&gt;Seventy percent of websites still fail basic WCAG contrast checks in 2025. After years of design system tooling, accessibility linters, and JavaScript libraries, nothing moved the needle. We didn’t need better libraries. We needed better CSS.&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-style: normal; font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;contrast-color()&lt;/code&gt;&amp;nbsp;is that better CSS.&lt;/section&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 1.1em; grid-column-end: 13; grid-column-start: 3; line-height: 1.55em; margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The&amp;nbsp;&lt;a href="https://almanac.httparchive.org/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;HTTP Archive Web Almanac&lt;/a&gt;&amp;nbsp;has been tracking color contrast failures for years. The numbers have barely moved. After half a decade of design system tooling, accessibility linters, and entire JavaScript libraries dedicated to computing readable text colors,&amp;nbsp;&lt;a href="https://almanac.httparchive.org/en/2025/accessibility#color-contrast" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;70% of websites still fail basic WCAG contrast checks in 2025&lt;/a&gt;. The&amp;nbsp;&lt;a href="https://webaim.org/projects/million/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;WebAIM Million&lt;/a&gt;&amp;nbsp;paints an even grimmer picture — 83.9% of homepages flagged for low contrast text in 2026, up from 79.1% in 2025. The rate improves by maybe a few percentage points per year on one benchmark and actually gets&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;worse&lt;/em&gt;&amp;nbsp;on another. That’s not progress — that’s proof that relying on runtime JavaScript for something this fundamental doesn’t scale across the open web. We didn’t need better libraries. We’ve needed better CSS.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;contrast-color()&lt;/code&gt;&amp;nbsp;function is that better CSS. One declaration. The browser runs the contrast math during style computation, before the page paints, and hands you the right text color. No library, no build step, no hydration flash.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Note&lt;/span&gt;: If you’ve seen it called&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;color-contrast()&lt;/code&gt;&amp;nbsp;in older articles and spec drafts —&amp;nbsp;&lt;a href="https://github.com/w3c/csswg-drafts/issues/7557" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;that name was changed&lt;/a&gt;, and the old syntax no longer works in any browser.&lt;/p&gt;&lt;h2 id="what-it-does-and-what-it-doesn-t" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;What It Does (And What It Doesn’t)&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/building-self-correcting-color-systems-contrast-color/#what-it-does-and-what-it-doesn-t" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The Level 5 version is simple. You give it a color. It gives you back&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;black&lt;/code&gt;&amp;nbsp;or&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;white&lt;/code&gt;, whichever has more contrast against your input.&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-css" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-css" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token selector" style="box-sizing: border-box; color: #2f9c0a;"&gt;.button&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;background-color&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;var&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;--brand-color&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;color&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;contrast-color&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;var&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;--brand-color&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Change&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;--brand-color&lt;/code&gt;&amp;nbsp;to neon green, text goes black. Change it to midnight navy, text goes white. Swap themes at runtime via JavaScript and the text adapts instantly — no event listeners, no recalculation.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;A few things to know about the current version:&lt;/p&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;It returns a&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&amp;lt;color&amp;gt;&lt;/code&gt;, not a number. You get an actual color value (&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;black&lt;/code&gt;&amp;nbsp;or&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;white&lt;/code&gt;), you can use anywhere CSS accepts a color.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Black or white only&lt;/span&gt;, for now. Candidate color lists and target ratios are planned for Level 6.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;No keywords.&lt;/span&gt;&amp;nbsp;If you’ve seen&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;max&lt;/code&gt;&amp;nbsp;in older blog posts, that was stripped from the spec. Using it will silently break your declaration.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;As mentioned above, this function used to be called&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;color-contrast()&lt;/code&gt;&amp;nbsp;in early drafts. That name is dead —&amp;nbsp;&lt;a href="https://github.com/w3c/csswg-drafts/issues/7557" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;the CSSWG renamed it&lt;/a&gt;&amp;nbsp;to follow the convention that CSS functions are named for what they return.&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;color-mix()&lt;/code&gt;&amp;nbsp;returns a color.&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;contrast-color()&lt;/code&gt;&amp;nbsp;returns a color. The old&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;color-contrast()&lt;/code&gt;&amp;nbsp;name sounded like it returned a contrast&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;ratio&lt;/em&gt;&amp;nbsp;(a number like 4.5), which was misleading. Any tutorial from 2021–2023 showing&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;color-contrast()&lt;/code&gt;&amp;nbsp;syntax won’t work in current browsers.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="font-size: calc(1.5rem + 0.25vw); text-transform: capitalize;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="font-size: calc(1.5rem + 0.25vw); text-transform: capitalize;"&gt;The Spec Split: Level 5 Versus Level 6&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;This function lives across two specifications. That’s unusual and worth understanding.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;a href="https://www.w3.org/TR/css-color-5/#contrast-color" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;CSS Color Level 5&lt;/span&gt;&lt;/a&gt;&amp;nbsp;defines what browsers ship today. One color in, black or white out. The algorithm is deliberately marked “UA-defined”, meaning the browser decides what math to use internally. Right now, every engine uses WCAG 2.x relative luminance. But that “UA-defined” label isn’t accidental — it’s a planned escape hatch.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;You’ll see APCA (&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Accessible Perceptual Contrast Algorithm&lt;/span&gt;) mentioned a lot in this context. APCA models how human eyes actually perceive contrast, factoring in font weight, spatial frequency, and ambient light — a genuine improvement over the WCAG 2.x formula. By not locking&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;“use WCAG 2.x”&lt;/em&gt;&amp;nbsp;into the Level 5 spec, browser vendors&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;could&lt;/em&gt;&amp;nbsp;swap to APCA later without breaking any existing code. If the spec had shipped with a&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;wcag2()&lt;/code&gt;&amp;nbsp;keyword as the default, every site using it would’ve been stuck on the old math permanently.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;But APCA’s future is far less certain than the hype suggests. Adrian Roselli’s “&lt;a href="https://adrianroselli.com/2026/04/wcag3-contrast-as-of-april-2026.html" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;WCAG3 Contrast as of April 2026&lt;/a&gt;” lays out the current situation clearly: APCA was pulled from the WCAG 3 working draft&amp;nbsp;&lt;a href="https://www.w3.org/TR/2023/WD-wcag-3.0-20230724/#color-and-contrast" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;in mid-2023&lt;/a&gt;&amp;nbsp;after failing to gain enough Working Group support. The WCAG 3 spec currently says the contrast algorithm is&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;“yet to be determined,”&lt;/em&gt;&amp;nbsp;and the standard itself&amp;nbsp;&lt;a href="https://www.w3.org/WAI/standards-guidelines/wcag/wcag3-intro/#timeline" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;may not be finalized until 2030 or later&lt;/a&gt;. Roselli also&amp;nbsp;&lt;a href="https://issues.chromium.org/issues/341439947" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;filed a Chromium issue in May 2024&lt;/a&gt;&amp;nbsp;asking for the “Advanced Perceptual Contrast Algorithm” experiment flag to be removed from DevTools entirely, arguing that the implementation is outdated and risks misleading developers into thinking APCA is further along — or more official — than it actually is. That issue is still open.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;None of this means APCA is dead. The research behind it is peer-reviewed and substantive, and its creator&amp;nbsp;&lt;a href="https://adrianroselli.com/2026/04/wcag3-contrast-as-of-april-2026.html#comment-408186" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;has noted&lt;/a&gt;&amp;nbsp;that colors passing APCA guidelines greatly exceed WCAG 2 minimums in the vast majority of cases. But right now, there is no guarantee APCA will be the algorithm that replaces WCAG 2.x — and that uncertainty matters for&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;contrast-color()&lt;/code&gt;. If a different algorithm wins out, or if WCAG 3 adopts something entirely new, the “UA-defined” label means browsers can adapt without breaking your code. It also means the Level 6 features — candidate color lists, target ratios, the&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;tbd-fg&lt;/code&gt;/&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;tbd-bg&lt;/code&gt;&amp;nbsp;keywords — are all designed around an algorithm that may or may not materialize in its current form.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;CSS Color Level 6&lt;/span&gt;&amp;nbsp;adds the extended syntax — candidate color lists and target contrast ratios:&lt;/p&gt;&lt;div class="break-out" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 14; grid-column-start: 3; margin-bottom: 1.4em; margin-top: 0px; width: 774.9375px;"&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; margin-bottom: 0px; position: relative;"&gt;&lt;pre class=" language-css" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-css" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;/* Level 6 future syntax — not shipping yet */&lt;/span&gt;
&lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;color&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;contrast-color&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;var&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;--bg&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; tbd-bg &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;wcag2&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;aa&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; #1a1a2e&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; #e2e8f0&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; #fbbf24&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The browser would evaluate each candidate left to right and pick the first that meets the 4.5:1 AA threshold. The&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;tbd-fg&lt;/code&gt;&amp;nbsp;and&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;tbd-bg&lt;/code&gt;&amp;nbsp;keywords indicate whether the base color is foreground or background, which matters for directional contrast models like APCA. This is all Working Draft territory — doubly so given APCA’s uncertain status. Use the Level 5 version for now.&lt;/p&gt;&lt;h2 id="browser-support" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Browser Support&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;This one’s in better shape than most new CSS features. All three major engines have shipped it in stable releases:&amp;nbsp;&lt;a href="https://chromestatus.com/feature/40142548" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Chrome 147&lt;/a&gt;&amp;nbsp;(April 2026),&amp;nbsp;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/contrast-color" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Firefox 146&lt;/a&gt;, and&amp;nbsp;&lt;a href="https://developer.apple.com/documentation/safari-release-notes/safari-26-release-notes" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Safari 26.0&lt;/a&gt;. It reached&amp;nbsp;&lt;a href="https://web.dev/baseline/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Baseline Newly Available&lt;/a&gt;&amp;nbsp;status in April 2026. Check&amp;nbsp;&lt;a href="https://caniuse.com/mdn-css_types_color_contrast-color" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;caniuse&lt;/a&gt;&amp;nbsp;for the full version matrix. All three engines pass the Web Platform Tests for&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;contrast-color()&lt;/code&gt;, which means the edge cases (e.g., tie-breaking logic, color space conversion, syntax parsing) behave the same across browsers.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The raw global support percentage on caniuse looks low, but that mostly reflects enterprise browsers and people who never update. If you’re reading this, your browser almost certainly supports it already.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Progressive enhancement is straightforward using&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;@supports&lt;/code&gt;:&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-css" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-css" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token selector" style="box-sizing: border-box; color: #2f9c0a;"&gt;.card&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;background&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;var&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;--bg&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;color&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; #fff&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;text-shadow&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; 0 0 4px &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;rgb&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;0 0 0 / 0.8&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;

&lt;span class="token atrule" style="box-sizing: border-box; color: #0e82a9;"&gt;&lt;span class="token rule" style="box-sizing: border-box;"&gt;@supports&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;color&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;contrast-color&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;red&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token selector" style="box-sizing: border-box; color: #2f9c0a;"&gt;.card&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
    &lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;color&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;contrast-color&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;var&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;--bg&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
    &lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;text-shadow&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; none&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Older browsers get white text with a dark shadow for legibility. Supporting browsers get the native calculation. Nobody sees broken text.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;One thing to watch for: automated accessibility scanners (Lighthouse, Axe, etc.) can’t evaluate&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;text-shadow&lt;/code&gt;. They only look at the computed&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;color&lt;/code&gt;&amp;nbsp;against&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;background-color&lt;/code&gt;. So the fallback will still get flagged as a contrast failure in CI/CD pipelines, even if the shadow makes the text perfectly legible to human eyes. If your team runs automated a11y checks, you may need to allowlist that specific rule or add a comment explaining why the flag is a false positive.&lt;/p&gt;&lt;blockquote style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgba(245, 242, 240, 0.89) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-left-color: rgb(230, 228, 225); border-left-style: solid; border-left-width: 11px; border-radius: 11px; box-sizing: border-box; color: #424242; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 1.05em; font-style: italic; grid-column-end: 13; grid-column-start: 3; line-height: 1.65em; margin: 0.3em 0px 1.7em; padding: 1em calc(1.5em + 0.5vw);"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;A note on PostCSS&lt;/span&gt;:&lt;br style="box-sizing: border-box;" /&gt;&lt;br style="box-sizing: border-box;" /&gt;There’s a plugin (&lt;a href="https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-contrast-color-function" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-style: normal; font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;@csstools/postcss-contrast-color-function&lt;/code&gt;&lt;/a&gt;) that evaluates&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-style: normal; font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;contrast-color()&lt;/code&gt;&amp;nbsp;at build time. It works for static colors like&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-style: normal; font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;contrast-color(#ff0000)&lt;/code&gt;. But the moment you use a custom property —&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-style: normal; font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;contrast-color(var(--bg))&lt;/code&gt;&amp;nbsp;— the plugin can’t help because it has no access to runtime values. If your theming is dynamic (which is the whole point of doing this), skip the polyfill and rely on&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-style: normal; font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;@supports&lt;/code&gt;.&lt;/blockquote&gt;&lt;h2 id="the-gotchas" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;The Gotchas&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/building-self-correcting-color-systems-contrast-color/#the-gotchas" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;h3 id="it-doesn-t-guarantee-perceptual-or-aaa-compliance" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;IT DOESN’T GUARANTEE PERCEPTUAL OR AAA COMPLIANCE&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;This can trip people up:&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;“I used the contrast function, so my site passes accessibility checks now, right?”&lt;/em&gt;&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Mathematically? Usually yes. There is a persistent myth that for certain “mid-tone” backgrounds, both black and white fail the standard WCAG 4.5:1 AA ratio. That’s mathematically false. Under the WCAG 2.x relative luminance formula, there is absolutely no background color where both pure black and pure white fail AA. One (or both) will always pass.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Take&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;#2277d3&lt;/code&gt;&amp;nbsp;(a medium blue). It sits right on a mathematical knife-edge where both black and white actually pass AA (both hit roughly 4.58:1).&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;contrast-color()&lt;/code&gt;&amp;nbsp;will hand you whichever has the slight mathematical edge.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;But here is the actual gotcha: the WCAG 2.x math has known perceptual blind spots. That same&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;#2277d3&lt;/code&gt;&amp;nbsp;with black text mathematically passes AA, but to human eyes, it can be incredibly difficult to read.&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;contrast-color()&lt;/code&gt;&amp;nbsp;gives you&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;mathematical&lt;/em&gt;&amp;nbsp;compliance, which is great for automated audits, but that doesn’t always equal&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;perceptual&lt;/em&gt;&amp;nbsp;accessibility. (This is exactly why APCA exists and why the spec was designed to let browsers swap algorithms later.)&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Furthermore, if you’re aiming for the stricter WCAG AAA standard (7.0:1), a true dead zone&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;does&lt;/em&gt;&amp;nbsp;exist. For backgrounds with a luminance between roughly 10% and 30%, neither black nor white will hit 7:1. In those cases,&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;contrast-color()&lt;/code&gt;can’t save you — it just hands you the “least bad” failing option.&lt;/p&gt;&lt;h3 id="transitions-snap-not-fade" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;TRANSITIONS SNAP, NOT FADE&amp;nbsp;&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;If you’re animating a background from&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;white&lt;/code&gt;&amp;nbsp;to&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;black&lt;/code&gt;&amp;nbsp;on hover:&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-css" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-css" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token selector" style="box-sizing: border-box; color: #2f9c0a;"&gt;.btn&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;background-color&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; #fff&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;color&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;contrast-color&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;#fff&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt; &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;/* black */&lt;/span&gt;
  &lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;transition&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; background-color 1s&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; color 1s&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;span class="token selector" style="box-sizing: border-box; color: #2f9c0a;"&gt;.btn:hover&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;background-color&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; #000&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;color&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;contrast-color&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;#000&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt; &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;/* white */&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The background fades smoothly over one second. But because the Level 5 output is a&amp;nbsp;&lt;a href="https://www.w3.org/TR/css-transitions-1/#discrete" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;discrete value&lt;/a&gt;&amp;nbsp;(black or white), the text color can’t be interpolated. It snaps.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;And here is the visual gotcha: the snap doesn’t happen halfway through. If you’ve been building themes for a while, you probably have muscle memory from the old Sass days, where we checked if&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;lightness($bg) &amp;gt; 50%&lt;/code&gt;. That relied on HSL lightness, where 50% is the geometric midpoint.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;But WCAG 2.x relative luminance is a non-linear scale. Under the WCAG formula, the mathematical tipping point — where black and white have identical contrast against the background — actually occurs at approximately 18% relative luminance (specifically ~17.9%).&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Because of that, the visual behavior during a white-to-black fade is heavily skewed. The text doesn’t snap in the middle. It stays black for the vast majority of the animation, only snapping to white at the very tail-end of the transition when the background gets extremely dark. It’s a jarring, late hard cut.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;You might assume&amp;nbsp;&lt;a href="https://css-tricks.com/almanac/properties/t/transition/transition-behavior/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;transition-behavior: allow-discrete&lt;/code&gt;&lt;/a&gt;&amp;nbsp;fixes this. It doesn’t.&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;allow-discrete&lt;/code&gt;&amp;nbsp;does not fix the jarring visual experience because it cannot interpolate a binary output; it only shifts the timing of the hard snap to the 50% mark of the animation duration. If you need smooth text color transitions, you’ll have to layer&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;color-mix()&lt;/code&gt;&amp;nbsp;or manage the crossfade yourself.&lt;/p&gt;&lt;h3 id="tie-goes-to-white" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;TIE GOES TO WHITE&amp;nbsp;&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;If the background is a perfect middle gray where both black and white produce identical contrast ratios,&amp;nbsp;&lt;a href="https://www.w3.org/TR/css-color-5/#contrast-color" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;the spec has a hardcoded tiebreaker&lt;/a&gt;: white wins. Not a big deal in practice, but worth knowing if you’re debugging gray palettes and the text isn’t doing what you expect.&lt;/p&gt;&lt;h3 id="gradients-and-images-are-out" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;GRADIENTS AND IMAGES ARE OUT&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/building-self-correcting-color-systems-contrast-color/#gradients-and-images-are-out" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The function takes a flat&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&amp;lt;color&amp;gt;&lt;/code&gt;&amp;nbsp;value. You can’t pass it a gradient or a&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;url()&lt;/code&gt;.&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;contrast-color(linear-gradient(...))&lt;/code&gt;&amp;nbsp;is a parse error. If your background is a photo or a complex gradient, you still need JavaScript or manually color-pick for overlay text.&lt;/p&gt;&lt;h3 id="transparent-colors-are-composited-first" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;TRANSPARENT COLORS ARE COMPOSITED FIRST&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/building-self-correcting-color-systems-contrast-color/#transparent-colors-are-composited-first" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Pass a semi-transparent color, and the browser blends it against an assumed opaque canvas (usually white) before running the contrast math. It’s not ignoring your alpha channel — it’s compositing it. But the result might surprise you if you expected the function to “see through” to whatever’s actually behind the element.&lt;/p&gt;&lt;h3 id="windows-high-contrast-mode" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;WINDOWS HIGH CONTRAST MODE&amp;nbsp;&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;If a user enables Windows High Contrast, the&amp;nbsp;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/forced-colors" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;forced-colors: active&lt;/code&gt;&lt;/a&gt;&amp;nbsp;media query kicks in and the browser aggressively overwrites author-defined colors.&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;contrast-color()&lt;/code&gt;&amp;nbsp;bows out —&amp;nbsp;&lt;a href="https://www.w3.org/TR/css-color-adjust-1/#forced-colors-mode" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;forced system colors&lt;/a&gt;&amp;nbsp;like&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;CanvasText&lt;/code&gt;&amp;nbsp;take over completely. You don’t need to write manual media queries to undo your contrast logic; the browser handles the hierarchy.&lt;/p&gt;&lt;h2 id="combining-it-with-other-color-functions" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Combining It With Other Color Functions&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Black or white sounds limiting, but once you feed that output into other CSS color functions, you can build an entire component palette off a single custom property.&lt;/p&gt;&lt;h3 id="brand-tinted-contrast-with-relative-color-syntax" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;BRAND-TINTED CONTRAST WITH RELATIVE COLOR SYNTAX&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/building-self-correcting-color-systems-contrast-color/#brand-tinted-contrast-with-relative-color-syntax" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Pure black text on a vibrant card looks fine. Pure white on a coral card can feel flat. What if the contrast text was a very dark or very light&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;tint&lt;/em&gt;&amp;nbsp;of the background color instead?&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Kevin Hamer explored related territory in his CSS-Tricks piece “&lt;a href="https://css-tricks.com/approximating-contrast-color-with-other-css-features/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Approximating contrast-color() With Other CSS Features&lt;/a&gt;”, where he used OKLCH lightness and&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;round()&lt;/code&gt;&amp;nbsp;to approximate the black/white switch&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;without&lt;/em&gt;&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;contrast-color()&lt;/code&gt;&amp;nbsp;— essentially&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;oklch(from &amp;lt;color&amp;gt; round(1.21 - l) 0 0)&lt;/code&gt;. That’s a polyfill strategy: get the binary light/dark decision working in browsers that don’t support the native function yet. What we’re doing here is different — we&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;start&lt;/em&gt;with&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;contrast-color()&lt;/code&gt;’s native output and then enrich it by injecting the background’s own hue:&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-css" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-css" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token selector" style="box-sizing: border-box; color: #2f9c0a;"&gt;.card&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;--bg-hue&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; 260&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt; &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;/* Indigo */&lt;/span&gt;
  &lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;--bg&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;oklch&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;0.6 0.1 &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;var&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;--bg-hue&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;background&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;var&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;--bg&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

  &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;/* Pull L from the black/white contrast color,
     but inject subtle chroma and the background's hue */&lt;/span&gt;
  &lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;color&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;oklch&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;from &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;contrast-color&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;var&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;--bg&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; l 0.05 &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;var&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;--bg-hue&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;When&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;contrast-color()&lt;/code&gt;&amp;nbsp;returns white,&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;l&lt;/code&gt;&amp;nbsp;is 1 (full lightness). When it returns black,&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;l&lt;/code&gt;&amp;nbsp;is 0. By pulling the background’s hue back in and adding a touch of chroma, you get text that reads as a deep dark indigo or a pale icy indigo instead of generic black/white. Hamer’s approach gives you the black/white decision without browser support; this one takes the decision the browser already made and gives it personality.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Fair warning&lt;/span&gt;: By tweaking the lightness and chroma of the black/white output, you can push a borderline contrast ratio into failing territory. Always run your tinted output through an accessibility linter before shipping.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Also worth noting&lt;/span&gt;: This example chains two very modern features —&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;contrast-color()&lt;/code&gt;&amp;nbsp;and&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;oklch(from ...)&lt;/code&gt;. If either one isn’t supported, the entire declaration fails silently. Your&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;@supports&lt;/code&gt;&amp;nbsp;block needs to test for both:&lt;/p&gt;&lt;div class="break-out" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 14; grid-column-start: 3; margin-bottom: 1.4em; margin-top: 0px; width: 774.9375px;"&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; margin-bottom: 0px; position: relative;"&gt;&lt;pre class=" language-css" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-css" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token atrule" style="box-sizing: border-box; color: #0e82a9;"&gt;&lt;span class="token rule" style="box-sizing: border-box;"&gt;@supports&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;color&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;contrast-color&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;red&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box;"&gt;and&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;color&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;oklch&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;from red l c h&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;/* Safe to use both */&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="softened-contrast-with-color-mix" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;SOFTENED CONTRAST WITH&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; text-transform: none; word-break: normal; word-spacing: normal;"&gt;color-mix()&lt;/code&gt;&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/building-self-correcting-color-systems-contrast-color/#softened-contrast-with-color-mix" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Similar idea, simpler API. Mix the sharp black/white output back into the background to soften it:&lt;/p&gt;&lt;div class="break-out" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 14; grid-column-start: 3; margin-bottom: 1.4em; margin-top: 0px; width: 774.9375px;"&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; margin-bottom: 0px; position: relative;"&gt;&lt;pre class=" language-css" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-css" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token selector" style="box-sizing: border-box; color: #2f9c0a;"&gt;.alert&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;--bg&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;var&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;--alert-color&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;background&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;var&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;--bg&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

  &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;/* 80% contrast, 20% background = softer but readable */&lt;/span&gt;
  &lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;color&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;color-mix&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;in oklch&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;contrast-color&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;var&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;--bg&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; 80%&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;var&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;--bg&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

  &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;/* 40% contrast for a subtle border */&lt;/span&gt;
  &lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;border&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; 1px solid
    &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;color-mix&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;in oklch&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;contrast-color&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;var&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;--bg&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; 40%&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;var&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;--bg&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;One custom property driving text, border, and potentially&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;box-shadow&lt;/code&gt;&amp;nbsp;or&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;outline&lt;/code&gt;. Change&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;--alert-color&lt;/code&gt;&amp;nbsp;and the entire component recalculates.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;This pattern also works well for&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;::placeholder&lt;/code&gt;&amp;nbsp;text, which is a common pain point in dynamic theming. Placeholder text should be readable but visually softer than the input’s main text —&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;color-mix()&lt;/code&gt;&amp;nbsp;with&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;contrast-color()&lt;/code&gt;&amp;nbsp;gets you there:&lt;/p&gt;&lt;div class="break-out" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 14; grid-column-start: 3; margin-bottom: 1.4em; margin-top: 0px; width: 774.9375px;"&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; margin-bottom: 0px; position: relative;"&gt;&lt;pre class=" language-css" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-css" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token selector" style="box-sizing: border-box; color: #2f9c0a;"&gt;input&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;--bg&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;var&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;--input-bg&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;background&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;var&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;--bg&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;color&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;contrast-color&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;var&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;--bg&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;

&lt;span class="token selector" style="box-sizing: border-box; color: #2f9c0a;"&gt;input::placeholder&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;color&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;color-mix&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;in oklch&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;contrast-color&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;var&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;--bg&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; 50%&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;var&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;--bg&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;50%&lt;/code&gt;&amp;nbsp;mix gives you a muted but legible placeholder that adapts automatically to whatever background the input sits on.&lt;/p&gt;&lt;h3 id="theme-aware-contrast-with-light-dark" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;THEME-AWARE CONTRAST WITH&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; text-transform: none; word-break: normal; word-spacing: normal;"&gt;light-dark()&lt;/code&gt;&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/building-self-correcting-color-systems-contrast-color/#theme-aware-contrast-with-light-dark" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;For apps that support system light/dark mode:&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-css" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-css" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token selector" style="box-sizing: border-box; color: #2f9c0a;"&gt;:root&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;color-scheme&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; light dark&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;--surface&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;light-dark&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;#fff&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; #121212&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;

&lt;span class="token selector" style="box-sizing: border-box; color: #2f9c0a;"&gt;.component&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;background&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;var&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;--surface&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;color&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;contrast-color&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;var&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;--surface&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;When the operating system switches to dark mode,&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;--surface&lt;/code&gt;&amp;nbsp;resolves to&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;#121212&lt;/code&gt;, and&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;contrast-color()&lt;/code&gt;&amp;nbsp;returns white. No media queries, no JavaScript theme detection. The whole chain resolves natively.&lt;/p&gt;&lt;h2 id="what-you-can-remove-from-your-bundle" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;What You Can Remove From Your Bundle&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/building-self-correcting-color-systems-contrast-color/#what-you-can-remove-from-your-bundle" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The practical payoff: every one of these libraries existed because CSS couldn’t do contrast math. If you’re only using them for readable-text-color selection, you can pull them out of your runtime entirely:&lt;/p&gt;&lt;table class="tablesaw break-out" style="border-collapse: collapse; caret-color: rgb(51, 51, 51); clear: both; color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; font-variant-caps: normal; grid-column-end: 14; grid-column-start: 3; margin-bottom: 1.4em; margin-top: 0px; max-width: fit-content; width: 714.0625px;"&gt;&lt;thead style="box-sizing: border-box;"&gt;&lt;tr style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 4px; box-sizing: border-box;"&gt;&lt;th style="border-color: currentcolor currentcolor rgb(221, 221, 221); border-image: none; border-style: none none solid; border-width: medium medium 4px; box-sizing: border-box; font-family: Mija, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; padding: 0.8em 1em; text-align: left;"&gt;Library&lt;/th&gt;&lt;th style="border-color: currentcolor currentcolor rgb(221, 221, 221); border-image: none; border-style: none none solid; border-width: medium medium 4px; box-sizing: border-box; font-family: Mija, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; padding: 0.8em 1em; text-align: left;"&gt;Size&lt;/th&gt;&lt;th style="border-color: currentcolor currentcolor rgb(221, 221, 221); border-image: none; border-style: none none solid; border-width: medium medium 4px; box-sizing: border-box; font-family: Mija, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; padding: 0.8em 1em; text-align: left;"&gt;What it did&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody style="box-sizing: border-box;"&gt;&lt;tr style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 4px; box-sizing: border-box;"&gt;&lt;td data-label="Library" style="border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;chroma-js&lt;/td&gt;&lt;td data-label="Size" style="border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;~14 kB&lt;/td&gt;&lt;td data-label="What it did" style="border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;Color parsing, luminance calc, readable color selection&lt;/td&gt;&lt;/tr&gt;&lt;tr style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 4px; box-sizing: border-box;"&gt;&lt;td data-label="Library" style="background-color: #f7f7f7; border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;polished&lt;/td&gt;&lt;td data-label="Size" style="background-color: #f7f7f7; border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;~11 kB&lt;/td&gt;&lt;td data-label="What it did" style="background-color: #f7f7f7; border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;readableColor()&lt;/code&gt;&amp;nbsp;for styled-components&lt;/td&gt;&lt;/tr&gt;&lt;tr style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 4px; box-sizing: border-box;"&gt;&lt;td data-label="Library" style="border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;tinycolor2&lt;/td&gt;&lt;td data-label="Size" style="border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;~5 kB&lt;/td&gt;&lt;td data-label="What it did" style="border: medium; box-sizing: border-box; font-family: Elena; line-height: 33.490875px; padding: 0.8em 1em; vertical-align: middle;"&gt;Hex parsing, WCAG contrast ratio math&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;You might still need these for generating complex color scales, but the contrast-for-readability use case is now covered natively.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Beyond bundle size, there’s a performance angle that’s easy to overlook. Those JavaScript libraries don’t just cost you network bytes — they run on the main thread. Every time a theme changes or a component mounts with a dynamic background, your JS has to parse the color, compute luminance, decide black or white, and write the result back to the DOM. That’s main-thread work competing with layout, event handlers, and everything else your app is doing.&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;contrast-color()&lt;/code&gt;&amp;nbsp;moves all of that into the browser’s native style computation phase — heavily optimized C++ that runs before paint. For apps with lots of themed components, that’s a real difference in responsiveness.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;There’s also a subtle bug that goes away:&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;hydration flash&lt;/span&gt;. In React or Vue SSR apps, the server renders HTML without JavaScript. The client then hydrates, running JS to calculate contrast and inject the correct text color. For a brief window between initial paint and hydration, the text is either invisible or the wrong color. Moving contrast into CSS eliminates that entirely — the browser resolves the correct color during the initial paint, before JavaScript loads.&lt;/p&gt;&lt;h2 id="what-we-used-to-do" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;What We Used To Do&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/building-self-correcting-color-systems-contrast-color/#what-we-used-to-do" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;For context on what this replaces:&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Sass era.&lt;/span&gt;&amp;nbsp;You’d write a function that checked&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;lightness($bg) &amp;gt; 50%&lt;/code&gt;&amp;nbsp;and returned black or white at compile time. Worked for static themes. Completely useless for user-picked colors, CMS palettes, or dark mode, because the output was baked into the CSS file and could never change at runtime.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;The variable toggle hack.&lt;/span&gt;&amp;nbsp;When CSS custom properties shipped, people got creative. GitHub used a version of this for their issue label picker — splitting colors into&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;--r&lt;/code&gt;,&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;--g&lt;/code&gt;,&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;--b&lt;/code&gt;&amp;nbsp;channels, calculating Rec.709 luminance inside&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;calc()&lt;/code&gt;, multiplying by negative infinity, and clamping to&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;0&lt;/code&gt;&amp;nbsp;or&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;1&lt;/code&gt;. It worked. It was also unreadable, unmaintainable, and would break silently if you got one parenthesis wrong. (Kevin Hamer’s&amp;nbsp;&lt;a href="https://css-tricks.com/approximating-contrast-color-with-other-css-features/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;OKLCH-based approximation&lt;/a&gt;&amp;nbsp;is the most elegant version of this lineage — cleaner math, better perceptual alignment — but it’s still a workaround for a function that now ships natively.)&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;contrast-color()&lt;/code&gt;&amp;nbsp;replaces all of these approaches with a single function call. And because the spec lets browsers upgrade the underlying algorithm, your code won’t need to change if and when a successor to WCAG 2.x contrast math lands — whether that’s APCA or something else entirely.&lt;/p&gt;&lt;hr style="background: rgb(211, 58, 44); border-radius: 11px; box-sizing: content-box; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; height: 4px; margin: 0px; overflow: visible;" /&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;br style="box-sizing: border-box;" /&gt;&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;That&amp;nbsp;&lt;a href="https://almanac.httparchive.org/en/2025/accessibility#color-contrast" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;70% failure rate&lt;/a&gt;&amp;nbsp;was never about developers refusing to care about contrast. It was about the distance between caring and shipping — the library, the build step, the runtime calculation, the hydration flash, the one component someone forgot to wire up. Every gap in that chain was a spot where accessibility quietly dropped out.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;contrast-color()&lt;/code&gt;&amp;nbsp;doesn’t make developers care more. It makes caring cost nothing.&lt;/p&gt;</description><link>http://honeyvig.blogspot.com/2026/06/algorithmic-theming-engines-building.html</link><author>noreply@blogger.com (H)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-9165069509664255576.post-4289569465905048165</guid><pubDate>Tue, 02 Jun 2026 14:27:37 +0000</pubDate><atom:updated>2026-06-02T07:27:37.736-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Tools</category><category domain="http://www.blogger.com/atom/ns#">User experience</category><title>Rethinking The Experience Of System Tools</title><description>&lt;div class="c-garfield-summary" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 1.4em; margin-top: 0px;"&gt;&lt;section aria-label="Quick summary" class="article__summary" style="align-self: center; border-bottom-color: rgb(229, 229, 229); border-bottom-style: solid; border-bottom-width: 3px; box-sizing: border-box; color: #666666; font-size: 1.15em; font-style: italic; line-height: 1.55em; margin-bottom: 0.5em; margin-top: 0px; padding-bottom: 1.5em; position: initial;"&gt;Design always starts with function — function shapes form. But if that function can’t be made completely invisible and people still have to interact with it, it inevitably becomes part of their experience. In this article, Kyrylo Levashov explains why the question has shifted from, “Should your utility software feel better to use?” to “Can your utility software afford not to?“&lt;/section&gt;&lt;/div&gt;&lt;div class="sponsor-panel c-felix-the-cat" style="align-items: center; background: rgb(41, 60, 80); border-left: 11px solid var(--feature-panel-bg-color,#1c313a); border-radius: 11px; box-sizing: border-box; color: #e5e5e5; display: flex; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 1.05em; grid-column-end: 13; grid-column-start: 3; justify-content: center; line-height: 1.6em; margin-bottom: 1.4em; margin-left: 0px; margin-top: 0px; padding: 1em 1em 1em 1.5em; text-shadow: none;"&gt;&lt;p class="sponsor-panel-content" style="box-sizing: border-box; flex: 3 1 0%; line-height: calc(1.5em + 0.2vw); word-break: break-word;"&gt;This article has been kindly supported by our dear friends at&amp;nbsp;&lt;a href="https://macpaw.com/?utm_source=smashing&amp;amp;utm_medium=pr&amp;amp;utm_campaign=article" style="box-sizing: border-box; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;MacPaw&lt;/a&gt;&amp;nbsp;who not only believe that making great products requires seeing the world in a different light, but also strive to innovate and create incredible software ecosystem for users’ Macs.&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;Thank you!&lt;/em&gt;&lt;/p&gt;&lt;a class="sponsor-panel-image" href="https://macpaw.com/" style="background-image: none; box-sizing: border-box; color: #006fc6; display: block; flex: 1 1 0%; margin-left: 1.5em; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;&lt;img alt="MacPaw" loading="eager" src="https://files.smashing.media/articles/vertical-logo-white-macpaw.svg" style="border-style: none; box-sizing: border-box; max-width: 100%; position: relative;" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 1.1em; grid-column-end: 13; grid-column-start: 3; line-height: 1.55em; margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Your grandmother’s vacuum was a trusty but ugly workhorse hidden in a dark closet. Dyson turned that practical tool into an aspirational product, one you love leaving out even when guests come over. Dish soap was just dish soap until Method put it in a glass container, and it became an addition to, not a distraction from, the aesthetics of your kitchen. Physical product brands spent the last two decades transforming mundane, practical items like soap and vacuums into must-have experiences.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;But utility software — especially maintenance tools, a type of system software designed to analyze, configure, optimize, and maintain a computer — hasn’t made that leap from something you open as a chore to an experience you choose with excitement. And that means those brands are missing an interesting design opportunity: these tools are well overdue for a more intelligent, more human, and less emotionally flat approach.&lt;/p&gt;&lt;h2 id="the-most-underexplored-frontier-in-ux-is-the-maintenance-layer" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;“The Most Underexplored Frontier In UX Is The Maintenance Layer.”&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Utility software still feels like a chore. Using it has all the excitement of pulling out that dusty old vacuum from the back of the closet. These four common software design assumptions illustrate why the category hasn’t yet transcended its chore status.&lt;/p&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Assuming the user already resents the task&lt;/span&gt;: they’re here because something is wrong, not because they chose to open this tool. Designing accordingly means assuming they want the software to be fast, clinical, invisible, and something to get out of the way, not get into. But a design built for resentment produces tools that deserve it. If you expect your users to want to get out of the product as fast as possible, they’ll feel it in the design.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Assuming function is enough and feelings are for consumer apps&lt;/span&gt;: emotion in interface design is decoration. The maintenance layer is infrastructure, and nobody decorates infrastructure. But nobody decorated dish soap either, until Method. They didn’t change the product, just the user’s relationship to the tool they use to accomplish a task.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Assuming your users are not your fans because nobody cares about maintenance tools&lt;/span&gt;: utility tools don’t build communities, and nobody posts about running a disk cleanup. But people care deeply about tools that respect their time and make complex things simple for them to use. The MacPaw team listens to our community and implements many of the features they ask for, because we know users can be fans too, and they should shape how our products work.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Assuming that designers shouldn’t waste pixels on personality&lt;/span&gt;: you need to hide complexity and show minimal UI. Utility software should look neutral, technical, and forgettable.&lt;/li&gt;&lt;/ul&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;But when software hides the system, people lose trust in it.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Design always starts with function — function shapes form. But if that function can’t be made completely invisible and people still have to interact with it, it inevitably becomes part of their experience. In that case, people expect it not just to work, but to match their environment, influence their mood, and contribute to their overall experience.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;A good example is a watch. Its core function is simple: show the time. But because a watch occupies physical space in a person’s world, you want more from it than just functionality. It needs to play an aesthetic role and complement the environment.&lt;/p&gt;&lt;h2 id="the-maintenance-layer-is-a-behavioral-problem-not-just-a-ux-one" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;“The Maintenance Layer Is A Behavioral Problem, Not Just A UX One.”&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The user experience in utility software matters more than the industry tends to admit. In utility software, experience is not something added on top of function. It emerges from how the function is structured, explained, and interacted with. If you think you can design the most functional app on the market without considering how users understand and experience the process, you’re missing an opportunity to build a relationship with that user.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Part of that ignored UX element is a behavioral problem: users don’t avoid utility software because using it is hard, but instead because it produces&amp;nbsp;&lt;a href="https://research.macpaw.com/publications/emotional-assesments-ux" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;no positive emotional signal&lt;/a&gt;&amp;nbsp;at any point. The problem is rarely complex. It’s the absence of meaningful interaction during the process of using the app.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Another issue is focusing solely on function.&amp;nbsp;&lt;a href="https://uxmag.com/articles/the-aesthetic-usability-effect-why-beautiful-looking-products-are-preferred-over-usable-but-not-beautiful-ones" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;The aesthetic-usability effect&lt;/a&gt;&amp;nbsp;shows us clearly that if something looks better, it feels better — ATM screens in a 1995 study were judged easier to use if the screen layout was more attractive. Even something as purely functional as an ATM screen display needs attention to how the function is structured, presented, and perceived.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;And then there’s the memory problem. People remember&amp;nbsp;&lt;a href="https://www.researchgate.net/publication/5246508_Evaluations_of_Pleasurable_Experiences_The_Peak-End_Rule" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;the emotional peak and the ending of an experience&lt;/a&gt;, not the average. A completed process that ends with a clear “done” is remembered more positively than one that just fades out, even if the end task is completed successfully in both cases. System tools rarely intentionally design the ending of an interaction — they just stop running.&lt;/p&gt;&lt;h2 id="thoughtful-system-design-can-transform-maintenance-from-a-technical-chore-into-a-seamless-user-experience" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;“Thoughtful System Design Can Transform Maintenance From A Technical Chore Into A Seamless User Experience.”&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/rethinking-experience-system-tools/#thoughtful-system-design-can-transform-maintenance-from-a-technical-chore-into-a-seamless-user-experience" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;What does emotional design actually mean, then, in utility UX? Here are three principles the MacPaw team follows to design its products against the category norm.&lt;/p&gt;&lt;h3 id="translating-system-complexity-into-human-language" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;TRANSLATING SYSTEM COMPLEXITY INTO HUMAN LANGUAGE&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/rethinking-experience-system-tools/#translating-system-complexity-into-human-language" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Maintenance tools deal with storage, task management, and background processes. Good design explains what’s happening, avoids system jargon, and communicates outcomes clearly.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;a href="https://www.figma.com/blog/the-linear-method-opinionated-software/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Linear’s game-changing move&lt;/a&gt;&amp;nbsp;that illustrates this principle was agreeing on straightforward units of work, like projects and teams, that any new user can immediately understand. That helps them spend less time ramping up and more time building.&lt;/p&gt;&lt;h3 id="make-the-process-clear-and-show-progress" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;MAKE THE PROCESS CLEAR AND SHOW PROGRESS&amp;nbsp;&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;System tools run complex processes. Design should show progress, impact, and system change to create trust and control.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Vercel’s deployment infrastructure is an excellent example here. When you trigger a build, the browser tab favicon changes — a spinner while building, a green checkmark when done, a red X if it fails. It’s ruthlessly functional, not visual or warm, but it’s emotionally intelligent: it exists purely to reduce the low-level anxiety of waiting for a build to finish.&lt;/p&gt;&lt;h3 id="design-the-moment-of-completion" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;DESIGN THE MOMENT OF COMPLETION&amp;nbsp;&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Maintenance tasks often end quietly. But completion is the emotional payoff. Design should emphasize clarity of results, a sense of resolution, and visible improvement so users remember a positive and distinct ending.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Take the new CleanMyMac by MacPaw&amp;nbsp;&lt;a href="https://macpaw.com/news/introducing-new-cleanmymac" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;after its 2024 major update&lt;/a&gt;. Unlike the maintenance utility category norm, CleanMyMac uses visual language, including color, depth, motion, icons, and 3D illustrations, to shift the focus from diagnosing problems to showing progress: space cleared, threats removed, time saved. Instead of confronting the user with what’s wrong, the interface closes with a picture of a machine that’s already working better.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The task is the same, but the ending tells a different story, giving the user a picture of a machine that’s already working better.&lt;/p&gt;&lt;h2 id="even-if-you-don-t-care-about-emotional-design-as-a-principle-the-change-is-coming-anyway" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;“Even If You Don’t Care About Emotional Design As A Principle, The Change Is Coming Anyway.”&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/rethinking-experience-system-tools/#even-if-you-don-t-care-about-emotional-design-as-a-principle-the-change-is-coming-anyway" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The market is forcing this issue even for those who don’t find the argument I’ve made here compelling.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;That’s partly generational — designers and users who grew up with Linear, Figma, and Notion have a completely different baseline for the tools they use. Good software is not a happy accident for them, but a given. That generation is now the primary audience for maintenance software, and so the old “it’s fine, it’s just a utility” excuse doesn’t work philosophically or commercially. Just like Dyson and Method changed how entire product categories approached design, the current state of utility software is shifting for good.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;And digital fatigue is the current cultural state. The resurgence of vinyl records, film cameras, and dumbphones is not merely nostalgia, but a signal that the emotional relationship between people and their tools is changing.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The question has shifted from whether your utility software should feel better to use to whether it can afford not to.&lt;/p&gt;</description><link>http://honeyvig.blogspot.com/2026/06/rethinking-experience-of-system-tools.html</link><author>noreply@blogger.com (H)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-9165069509664255576.post-2427924343812979821</guid><pubDate>Tue, 02 Jun 2026 14:24:11 +0000</pubDate><atom:updated>2026-06-02T07:24:11.631-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Coding</category><category domain="http://www.blogger.com/atom/ns#">Designing Stable Interfaces For Streaming Content
UI</category><category domain="http://www.blogger.com/atom/ns#">UX</category><title>Designing Stable Interfaces For Streaming Content</title><description>&lt;div class="c-garfield-summary" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 1.4em; margin-top: 0px;"&gt;&lt;section aria-label="Quick summary" class="article__summary" style="align-self: center; border-bottom-color: rgb(229, 229, 229); border-bottom-style: solid; border-bottom-width: 3px; box-sizing: border-box; color: #666666; font-size: 1.15em; font-style: italic; line-height: 1.55em; margin-bottom: 0.5em; margin-top: 0px; padding-bottom: 1.5em; position: initial;"&gt;Streaming UIs are an easy concept on the surface, but are quite complicated in practice. There are many considerations that need to be accounted for, from layout shifts and motion preferences to proper markup and various states, that may not be instantly obvious. What happens if the stream is interrupted? Can users tab through the UI on the keyboard as it shifts? What ARIA attributes might be needed? Those are the sorts of things we will tackle in this article.&lt;/section&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 1.1em; grid-column-end: 13; grid-column-start: 3; line-height: 1.55em; margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;More interfaces now render while the response is still being generated. The UI begins in one state, then updates as more data comes in. You see this in chat apps, logs, transcription tools, and other real-time systems.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The tricky part is that the&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;interface is not in a fixed state&lt;/span&gt;; it keeps changing as new content comes in. It grows where lines become longer and new blocks appear. Something that was just below the screen can suddenly move, and the user’s scroll position becomes harder to manage. Parts of the UI might even be incomplete while the user is already interacting with it.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;In this article, we’ll take a simple interface and make it handle this properly. We’ll look at how to keep things stable, manage scrolling, and render partial content without breaking the reading experience.&lt;/p&gt;&lt;h2 id="what-does-a-streaming-ui-actually-look-like" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;What Does A Streaming UI Actually Look Like?&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/designing-stable-interfaces-streaming-content/#what-does-a-streaming-ui-actually-look-like" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;I’ve built three demos that stream content in different ways: a chat bubble, a log feed, and a transcription view. They look different on the surface, but they all run into the same three problems.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The first is&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;scroll&lt;/span&gt;. When content is streaming in, most interfaces keep the viewport pinned to the bottom. That works if you are just watching, but the moment you scroll up to read something, the page snaps back down. You did not ask for that. The interface decided for you, and now you’re fighting it instead of reading.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The second is&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;layout shift&lt;/span&gt;. Streaming content means containers are constantly growing, and as they do, everything below shifts downward. A button you were about to click is no longer where it was. A line you were reading has moved. The page is not broken; it is just that nothing stays still long enough to interact with comfortably.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The third is&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;render frequency&lt;/span&gt;. Browsers paint the screen around 60 times per second, but streams can arrive much faster than that. This means the DOM, which is the browser’s internal representation of everything on the page, ends up being updated for frames the user will never actually see. Each update still costs something, and that cost adds up quietly until performance starts to slip.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;As you go through each demo, pay attention to where things start feeling off. That small moment of friction when the interface starts getting in your way. This is exactly what we are here to fix&lt;/p&gt;&lt;h2 id="example-1-streaming-ai-chat-responses" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Example 1: Streaming AI Chat Responses&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/designing-stable-interfaces-streaming-content/#example-1-streaming-ai-chat-responses" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;This is the most familiar case. You click&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Stream&lt;/span&gt;, and the message starts growing token by token, just like a typical AI chat interface.&lt;/p&gt;&lt;figure style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 679.765625px;"&gt;&lt;a href="https://codesandbox.io/embed/swmjpl?view=preview" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="Streaming AI Chat Responses" decoding="async" fetchpriority="low" height="566" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/1-streaming-ai-chat-responses.png" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/1-streaming-ai-chat-responses.png 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/1-streaming-ai-chat-responses.png 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/1-streaming-ai-chat-responses.png 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/1-streaming-ai-chat-responses.png 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/1-streaming-ai-chat-responses.png 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; padding: 0.75em 2em 0.75em 0px;"&gt;Open in&amp;nbsp;&lt;a href="https://codesandbox.io/embed/swmjpl?view=preview" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;CodeSandbox&lt;/a&gt;. (&lt;a href="https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/1-streaming-ai-chat-responses.png" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Here’s what I want you to try:&lt;/p&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;Click the&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Stream&lt;/span&gt;&amp;nbsp;button.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;Try scrolling upwards while the message is streaming.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;Increase the speed (to something like 10ms).&lt;/li&gt;&lt;/ul&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;You will notice something subtle but important: the UI keeps trying to pull you back down. Basically, it is making a decision for you about where your attention should be.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;That’s one example. Let’s look at another.&lt;/p&gt;&lt;h2 id="example-2-live-processing-in-a-log-viewer" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Example 2: Live Processing In A Log Viewer&amp;nbsp;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;This example looks different on the surface, but the problem is actually very similar to the first example. Rather than a message that gets longer over time, new lines are appended continuously, like a terminal or a log stream.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The interesting part here is the tail toggle. It makes the trade-off between interaction and stable interfaces very clear:&lt;/p&gt;&lt;figure style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 679.765625px;"&gt;&lt;a href="https://codesandbox.io/embed/cytscf?view=preview" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="Live Processing In A Log Viewer" decoding="async" fetchpriority="low" height="515" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/2-live-processing-log-viewer.png" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/2-live-processing-log-viewer.png 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/2-live-processing-log-viewer.png 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/2-live-processing-log-viewer.png 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/2-live-processing-log-viewer.png 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/2-live-processing-log-viewer.png 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; padding: 0.75em 2em 0.75em 0px;"&gt;Open in&amp;nbsp;&lt;a href="https://codesandbox.io/embed/cytscf?view=preview" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;CodeSandbox&lt;/a&gt;. (&lt;a href="https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/2-live-processing-log-viewer.png" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Again, here is what I want you to try:&lt;/p&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;Click the&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Start&lt;/span&gt;&amp;nbsp;button.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;Allow the logs to stream past the container’s height.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;Scroll up to the beginning.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;Stop the stream and disable the “tail” option.&lt;/li&gt;&lt;/ul&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Notice that, when tail is enabled, the UI follows the new content. But you’re unable to scroll up and stay in place. Instead, you need to stop the stream or enable “tail” to explore the content.&lt;/p&gt;&lt;h2 id="example-3-dashboard-displaying-real-time-metrics" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Example 3: Dashboard Displaying Real-Time Metrics&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/designing-stable-interfaces-streaming-content/#example-3-dashboard-displaying-real-time-metrics" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;In this case, the UI updates in place:&lt;/p&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;Numbers change,&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;Charts shift,&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;Values refresh continuously.&lt;/li&gt;&lt;/ul&gt;&lt;figure style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 679.765625px;"&gt;&lt;a href="https://codesandbox.io/embed/8rtsrm?view=preview" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="Dashboard Displaying Real-Time Metrics" decoding="async" fetchpriority="low" height="402" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/3-dashboard-display-real-time-metrics.png" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/3-dashboard-display-real-time-metrics.png 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/3-dashboard-display-real-time-metrics.png 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/3-dashboard-display-real-time-metrics.png 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/3-dashboard-display-real-time-metrics.png 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/3-dashboard-display-real-time-metrics.png 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; padding: 0.75em 2em 0.75em 0px;"&gt;Open in&amp;nbsp;&lt;a href="https://codesandbox.io/embed/8rtsrm?view=preview" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;CodeSandbox&lt;/a&gt;. (&lt;a href="https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/3-dashboard-display-real-time-metrics.png" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;There is no scroll tension this time, but a different issue shows up. That’s what we’ll get into next.&lt;/p&gt;&lt;h2 id="why-the-ui-feels-unstable-and-how-to-fix-it" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Why The UI Feels Unstable And How To Fix It&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/designing-stable-interfaces-streaming-content/#why-the-ui-feels-unstable-and-how-to-fix-it" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;If you tried the chat demo and scrolled upward while the responses were coming in, you may have spotted the first issue right away: the UI keeps pulling you back down to the latest streamed content as it updates. This takes you out of context and never allows you the time to fully digest the content once it has passed.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;We see that exact same issue in the second example, the log viewer. Without the tail toggle, the streamed content overrides your scroll position.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;These aren’t bugs in the traditional sense that they produce code errors; rather, they are accessibility issues that affect&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;all&lt;/em&gt;&amp;nbsp;users. That said, they can be fixed and prevented with careful UX considerations as you plan and test your work.&lt;/p&gt;&lt;h3 id="ensure-predictable-scroll-behavior" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;ENSURE PREDICTABLE SCROLL BEHAVIOR&amp;nbsp;&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;This is the goal:&lt;/p&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;Enable auto-scrolling when detecting that the user is at the bottom of the stream.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;Stop auto-scrolling when the user has scrolled upwards.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;Resume auto-scrolling if the user scrolls back to the bottom of the stream.&lt;/li&gt;&lt;/ul&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;To do that, we need to know whether the user has intentionally moved away from the bottom, which we can assume is true when the scroll position is manually changed. We can track that behavior with a flag.&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;let&lt;/span&gt; userScrolled &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token boolean" style="box-sizing: border-box; color: #c92c2c;"&gt;false&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

chatEl&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;addEventListener&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'scroll'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;const&lt;/span&gt; gap &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; chatEl&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;scrollHeight
            &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;-&lt;/span&gt; chatEl&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;scrollTop
            &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;-&lt;/span&gt; chatEl&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;clientHeight&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

  userScrolled &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; gap &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;&amp;gt;&lt;/span&gt; &lt;span class="token number" style="box-sizing: border-box; color: #c92c2c;"&gt;60&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;That&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;60px&lt;/code&gt;&amp;nbsp;threshold matters. Without it, tiny layout changes (like a new line) would briefly create a gap and break auto-scroll, even if the user didn’t actually scroll.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Now let’s make sure that we enable auto-scrolling only when the user’s scroll position is equal to the stream’s scroll height, i.e., the user is at the bottom of the stream:&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;function&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;autoScroll&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;if&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;!&lt;/span&gt;userScrolled&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
    chatEl&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;scrollTop &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; chatEl&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;scrollHeight&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;One small thing that’s easy to miss: we need to reset&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;userScrolled&lt;/code&gt;&amp;nbsp;once a new stream begins. Otherwise, one scroll from a previous message can silently disable auto-scroll for the next one.&lt;/p&gt;&lt;h3 id="solidify-layout-stability" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;SOLIDIFY LAYOUT STABILITY&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/designing-stable-interfaces-streaming-content/#solidify-layout-stability" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;We saw this in the first example as well. As new content streams in, the layout jumps, or shifts, taking you out of your current context. To be specific about what’s shifting: it’s not the page layout in a broad sense, it’s the content directly below the chat bubble.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;There’s also a subtler artifact worth calling out before we look at the code: cursor flicker. Because we’re wiping&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;innerHTML&lt;/code&gt;&amp;nbsp;and recreating every element on every tick, the cursor is being destroyed and re-added constantly, up to 80 times per second at fast speeds.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;At normal speed, it’s easy to miss, but slow the slider down to around 30ms, and you’ll see a faint but persistent flicker at the end of the text. Once we fix the rebuild pattern, the flicker disappears entirely.&lt;/p&gt;&lt;figure class="video-embed-container break-out" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 14; grid-column-start: 3; margin: 0.3em auto 1.7em; padding: 0px; width: 774.9375px;"&gt;&lt;div class="video-embed-container--wrapper" style="box-sizing: border-box; height: 0px; max-width: 100%; overflow: hidden; padding-bottom: 435.890625px; position: relative; width: 774.9375px;"&gt;&lt;iframe allow="autoplay; fullscreen; picture-in-picture" allowfullscreen="" class="video-embed-container--wrapper-iframe" frameborder="0" src="https://player.vimeo.com/video/1187532028" style="border-style: none; border-width: 0px; box-sizing: border-box; height: 435.890625px; left: 0px; max-width: 100%; position: absolute; top: 0px; width: 774.9375px;"&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;That rebuild pattern is right here; this is what runs on every single incoming character:&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;bubble&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;innerHTML &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;''&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

fullText&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;split&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'\n'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;forEach&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token parameter" style="box-sizing: border-box;"&gt;line&lt;/span&gt; &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;const&lt;/span&gt; p &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; document&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;createElement&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'p'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  p&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;textContent &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; line &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;||&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'\u00A0'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  bubble&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;appendChild&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;p&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

bubble&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;appendChild&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;cursorEl&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;This works, but it’s expensive. Every update wipes the DOM and rebuilds it, forcing layout recalculation each time.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Now we write directly into a live node:&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;let&lt;/span&gt; currentP &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;null&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;function&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;initBubble&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token parameter" style="box-sizing: border-box;"&gt;bubble&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; cursor&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  currentP &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; document&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;createElement&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'p'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  currentP&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;appendChild&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;document&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;createTextNode&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;''&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  bubble&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;insertBefore&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;currentP&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; cursor&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;What we can do next is to create one paragraph with an empty text node and insert it before the cursor. That gives us a live node we can write into directly.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Then, for each character that arrives:&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;function&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;appendChar&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token parameter" style="box-sizing: border-box;"&gt;char&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; bubble&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; cursor&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;if&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;char &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;===&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'\n'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
    currentP &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; document&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;createElement&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'p'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
    currentP&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;appendChild&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;document&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;createTextNode&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;''&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
    bubble&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;insertBefore&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;currentP&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; cursor&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;else&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
    currentP&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;firstChild&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;textContent &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;+=&lt;/span&gt; char&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;For a regular character, we extend the text node by one character. The browser doesn’t need to recalculate the layout for that; the text grew, but nothing moved. For a newline, we create a fresh paragraph and move&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;currentP&lt;/code&gt;&amp;nbsp;forward. Layout recalculates once for that new paragraph, and that’s it.&lt;/p&gt;&lt;br /&gt;&lt;h3 id="render-frequency" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;RENDER FREQUENCY&amp;nbsp;&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;This one is most visible in the first example, the chat UI. Even with scrolling and a layout fixed, we’re still writing to the DOM on every single incoming character.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;When the stream is moving fast, you end up hammering the DOM with updates that don’t actually matter. The fix is straightforward: hold the incoming text in a buffer instead of writing it out immediately. Once you’ve collected enough, write it all to the DOM in one go; that’s what a&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;flush&lt;/span&gt;&amp;nbsp;is.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;To pull this off, we keep a simple buffer and make sure we only schedule a single update at a time. When it fires,&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;requestAnimationFrame&lt;/code&gt;&amp;nbsp;takes everything that has built up and writes it to the DOM in one shot.&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;let&lt;/span&gt; pending   &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;''&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;let&lt;/span&gt; rafQueued &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token boolean" style="box-sizing: border-box; color: #c92c2c;"&gt;false&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;When a new character streams in, we then add it to the buffer. If no flush is scheduled yet, we queue one:&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;function&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;onChar&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token parameter" style="box-sizing: border-box;"&gt;char&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  pending &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;+=&lt;/span&gt; char&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;if&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;!&lt;/span&gt;rafQueued&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
    rafQueued &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token boolean" style="box-sizing: border-box; color: #c92c2c;"&gt;true&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
    &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;requestAnimationFrame&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;flush&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;rafQueued&lt;/code&gt;&amp;nbsp;flag is important. Without it, every character would schedule its own frame, and you’d end up with dozens of unnecessary flushes.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;When the flush fires, it drains the entire buffer in one pass:&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;function&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;flush&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;for&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;const&lt;/span&gt; char &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;of&lt;/span&gt; pending&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
    &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;appendChar&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;char&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
  pending   &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;''&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  rafQueued &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token boolean" style="box-sizing: border-box; color: #c92c2c;"&gt;false&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;autoScroll&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;All the characters that arrive after the last frame are then rendered together, right before the browser paints them. Then we clear the buffer, reset the flag, and run auto-scroll once.&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;let&lt;/span&gt; userScrolled &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token boolean" style="box-sizing: border-box; color: #c92c2c;"&gt;false&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

chatEl&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;addEventListener&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'scroll'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;const&lt;/span&gt; gap &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; chatEl&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;scrollHeight
            &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;-&lt;/span&gt; chatEl&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;scrollTop
            &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;-&lt;/span&gt; chatEl&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;clientHeight&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

  userScrolled &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; gap &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;&amp;gt;&lt;/span&gt; &lt;span class="token number" style="box-sizing: border-box; color: #c92c2c;"&gt;60&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;function&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;autoScroll&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;if&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;!&lt;/span&gt;userScrolled&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
    chatEl&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;scrollTop &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; chatEl&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;scrollHeight&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;If the gap is small, we keep auto-scrolling. If it grows, we assume the user scrolled up, and we stop. That small threshold helps avoid jitter when new lines slightly change the height. Also, remember to reset&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;userScrolled&lt;/code&gt;&amp;nbsp;when a new stream starts.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Once scrolling is under control, another issue becomes obvious. As the message grows, it keeps shifting:&lt;/p&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;It starts as one line,&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;It expands, then&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;It pushes everything below it.&lt;/li&gt;&lt;/ul&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Nothing is technically broken, but it doesn’t feel stable. A common approach is to rebuild the whole message on every update:&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;bubble&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;innerHTML &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;''&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

fullText&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;split&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'\n'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;forEach&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token parameter" style="box-sizing: border-box;"&gt;line&lt;/span&gt; &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;const&lt;/span&gt; p &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; document&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;createElement&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'p'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  p&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;textContent &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; line &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;||&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'\u00A0'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  bubble&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;appendChild&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;p&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

bubble&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;appendChild&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;cursorEl&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;This works, but it is doing too much work. Every update destroys and rebuilds the DOM, forcing layout recalculation each time. That’s why everything keeps shifting. The idea is to write into the current paragraph and only create a new one when we actually hit a line break.&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;let&lt;/span&gt; currentP &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;null&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;function&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;initBubble&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token parameter" style="box-sizing: border-box;"&gt;bubble&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; cursor&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  currentP &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; document&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;createElement&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'p'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  currentP&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;appendChild&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;document&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;createTextNode&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;''&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  bubble&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;insertBefore&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;currentP&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; cursor&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;And then update it character by character:&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;function&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;appendChar&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token parameter" style="box-sizing: border-box;"&gt;char&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; bubble&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; cursor&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;if&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;char &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;===&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'\n'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
    currentP &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; document&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;createElement&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'p'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
    currentP&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;appendChild&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;document&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;createTextNode&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;''&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
    bubble&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;insertBefore&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;currentP&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; cursor&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;else&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
    currentP&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;firstChild&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;textContent &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;+=&lt;/span&gt; char&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Now we’re no longer rebuilding everything. Most updates just extend a text node, which is cheap and doesn’t trigger large layout shifts. It also fixes the small cursor flicker you might have noticed earlier, since we’re no longer removing and re-adding it.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;At this point, the UI already feels better, but there is still something subtle going on. We are still updating the DOM on every character. At higher speeds, that becomes a lot of small updates, many of which you never actually see.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Instead of rendering immediately, we can buffer the incoming characters and apply them once per frame.&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;let&lt;/span&gt; pending &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;''&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;let&lt;/span&gt; rafQueued &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token boolean" style="box-sizing: border-box; color: #c92c2c;"&gt;false&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;function&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;onChar&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token parameter" style="box-sizing: border-box;"&gt;char&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  pending &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;+=&lt;/span&gt; char&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;if&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;!&lt;/span&gt;rafQueued&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
    rafQueued &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token boolean" style="box-sizing: border-box; color: #c92c2c;"&gt;true&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
    &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;requestAnimationFrame&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;flush&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;At this point, we’re not touching the DOM yet, but only collecting characters as they arrive. Then, right before the next frame is painted, we flush everything at once:&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;function&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;flush&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;for&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;const&lt;/span&gt; char &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;of&lt;/span&gt; pending&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
    &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;appendChar&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;char&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;

  pending &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;''&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  rafQueued &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token boolean" style="box-sizing: border-box; color: #c92c2c;"&gt;false&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

  &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;autoScroll&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;These separate two things that were previously tied together:&lt;/p&gt;&lt;ol style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; counter-reset: listCounter 0; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: none; margin: 0px 0px 1.4em; max-width: 100%; padding: 0px;"&gt;&lt;li style="box-sizing: border-box; counter-increment: listCounter 1; line-height: calc(1.5em + 0.2vw); margin-bottom: 1em; padding-left: calc(1.65em + 0.7vw); position: relative; word-break: break-word;"&gt;How fast data arrives, and&lt;/li&gt;&lt;li style="box-sizing: border-box; counter-increment: listCounter 1; line-height: calc(1.5em + 0.2vw); margin-bottom: 1em; padding-left: calc(1.65em + 0.7vw); position: relative; word-break: break-word;"&gt;When the UI updates.&lt;/li&gt;&lt;/ol&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The result looks the same, but the browser does less work, resulting in the UI feeling smoother, especially when the stream is set to a faster speed.&lt;/p&gt;&lt;figure style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 679.765625px;"&gt;&lt;a href="https://codesandbox.io/embed/pk7tk5?view=preview" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="Broken vs. fixed" decoding="async" fetchpriority="low" height="566" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/4-broken-vs-fixed.png" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/4-broken-vs-fixed.png 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/4-broken-vs-fixed.png 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/4-broken-vs-fixed.png 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/4-broken-vs-fixed.png 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/4-broken-vs-fixed.png 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; padding: 0.75em 2em 0.75em 0px;"&gt;Open in&amp;nbsp;&lt;a href="https://codesandbox.io/embed/pk7tk5?view=preview" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;CodeSandbox&lt;/a&gt;. (&lt;a href="https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/4-broken-vs-fixed.png" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;None of these changes is a big effort on its own. But once they are in place, the interface stops reacting blindly to every update. It becomes easier to read, easier to control, and a lot less distracting, even though the content is still coming in continuously.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;There are even more considerations to take into account for ensuring a stable, predictable, and good user experience. For example, what happens if the stream is canceled mid-flow? And what can we do to ensure that user preferences are respected for things like reduced motion, keyboard navigation, and screen reader accessibility? Let’s get into those next.&lt;/p&gt;&lt;h2 id="handling-interrupted-streams" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Handling Interrupted Streams&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/designing-stable-interfaces-streaming-content/#handling-interrupted-streams" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Most streaming interfaces include a way to stop or cancel the stream. We saw that in the demos. But stopping often leaves the UI in an awkward state. The cursor might keep blinking, buttons don’t update, and the message just freezes mid-stream with no clear indication that it didn’t finish.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The problem is that the stop is usually wired to do one thing: cancel the timer. That’s not enough. You also need to (1) clear the pending buffer, (2) remove the cursor, (3) mark the response as incomplete, and (4) reset the buttons. Here’s how we accomplish those.&lt;/p&gt;&lt;h3 id="1-stop-the-stream-cleanly" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;1. STOP THE STREAM CLEANLY&amp;nbsp;&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Here’s what&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;stopStream&lt;/code&gt;&amp;nbsp;needs to do, in order:&lt;/p&gt;&lt;ol style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; counter-reset: listCounter 0; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: none; margin: 0px 0px 1.4em; max-width: 100%; padding: 0px;"&gt;&lt;li style="box-sizing: border-box; counter-increment: listCounter 1; line-height: calc(1.5em + 0.2vw); margin-bottom: 1em; padding-left: calc(1.65em + 0.7vw); position: relative; word-break: break-word;"&gt;Cancel the timer and flip the&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;isStreaming&lt;/code&gt;&amp;nbsp;flag so no more ticks run.&lt;/li&gt;&lt;li style="box-sizing: border-box; counter-increment: listCounter 1; line-height: calc(1.5em + 0.2vw); margin-bottom: 1em; padding-left: calc(1.65em + 0.7vw); position: relative; word-break: break-word;"&gt;Clear the&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;requestAnimationFrame&lt;/code&gt;&amp;nbsp;(RAF) buffer so nothing still queued gets written on the next frame.&lt;/li&gt;&lt;/ol&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;function&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;stopStream&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;clearTimeout&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;streamTimer&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  isStreaming &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token boolean" style="box-sizing: border-box; color: #c92c2c;"&gt;false&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  pending     &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;''&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  rafQueued   &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token boolean" style="box-sizing: border-box; color: #c92c2c;"&gt;false&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Clearing the&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;pending&lt;/code&gt;&amp;nbsp;property matters because there might be characters buffered from the last stream instance that haven’t been flushed yet. If you don’t clear it, the next&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;requestAnimationFrame&lt;/code&gt;&amp;nbsp;fires, drains the buffer, and writes those characters to the DOM after the stream has officially stopped.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Now we move on to removing the cursor by calling&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;markStopped&lt;/code&gt;&amp;nbsp;on the bubble:&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;if&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;cursorEl &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cursorEl&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;parentNode&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; cursorEl&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;remove&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;markStopped&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;aiBubble&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

  stopBtn&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;style&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;display  &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'none'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  retryBtn&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;style&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;display &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;''&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  playBtn&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;style&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;display  &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;''&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;setStatus&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'Stopped'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'stopped'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  chat&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;removeEventListener&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'scroll'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; onScroll&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;cursorEl.parentNode&lt;/code&gt;&amp;nbsp;check is there because&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;stopStream&lt;/code&gt;&amp;nbsp;is also called internally when a new message fires mid-stream, at which point the cursor might already be gone. Calling&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;remove()&lt;/code&gt;&amp;nbsp;on a detached node throws, so we check first.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;markStopped&lt;/code&gt;&amp;nbsp;appends a small label to the bottom of the bubble so the user knows the response didn’t finish:&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;function&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;markStopped&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token parameter" style="box-sizing: border-box;"&gt;bubble&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;if&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;!&lt;/span&gt;bubble&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;return&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  bubble&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;classList&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;add&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'stopped'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;const&lt;/span&gt; label &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; document&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;createElement&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'span'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  label&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;className &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'stopped-label'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  label&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;textContent &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'response stopped'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  bubble&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;appendChild&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;label&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The null check on&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;bubble&lt;/code&gt;&amp;nbsp;handles the edge case where stop fires before the AI message element has been initialized, which can happen if the user clicks stop during the 300ms delay before the bubble appears.&lt;/p&gt;&lt;h3 id="provide-a-retry-option" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;PROVIDE A RETRY OPTION&amp;nbsp;&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;If the stream simply stops — perhaps due to a network issue or some other unexpected error — we ought to provide the user with a path to re-attempt the stream. What that basically means is preventing the UI from doing the expensive work needed to scroll back up to the top, re-read the prompt, and retype it. With a retry option, the user only needs to click a button, and the stream restarts from the current position.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;To make that work, we need to hold onto the question when the stream starts:&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;let&lt;/span&gt; lastQuestion &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;''&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;function&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;startStream&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token parameter" style="box-sizing: border-box;"&gt;question&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; answer&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  lastQuestion &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; question&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// rest of setup...&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Then, when the retry attempt runs, we reset everything and start fresh:&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;function&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;retryStream&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;if&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;currentMsgEl &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;&amp;amp;&amp;amp;&lt;/span&gt; currentMsgEl&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;parentNode&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
    currentMsgEl&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;remove&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;

  charIndex    &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token number" style="box-sizing: border-box; color: #c92c2c;"&gt;0&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  userScrolled &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token boolean" style="box-sizing: border-box; color: #c92c2c;"&gt;false&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  pending      &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;''&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  rafQueued    &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token boolean" style="box-sizing: border-box; color: #c92c2c;"&gt;false&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  isStreaming  &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token boolean" style="box-sizing: border-box; color: #c92c2c;"&gt;true&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

  retryBtn&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;style&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;display &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'none'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  stopBtn&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;style&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;display  &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;''&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;setStatus&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'Streaming...'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'streaming'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

  chat&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;addEventListener&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'scroll'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; onScroll&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt; passive&lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;:&lt;/span&gt; &lt;span class="token boolean" style="box-sizing: border-box; color: #c92c2c;"&gt;true&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;

  &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;setTimeout&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
    &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;initAIMsg&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
    &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;tick&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;lastAnswer&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; &lt;span class="token number" style="box-sizing: border-box; color: #c92c2c;"&gt;200&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The reset is critical. Every piece of state needs to go back to its initial value, just like a brand new stream.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Note:&lt;/span&gt;&amp;nbsp;We remove the entire message row (&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;currentMsgEl&lt;/code&gt;), not just the bubble. If only the bubble is removed, the layout wrapper and avatar remain persistent and break the structure.&lt;/p&gt;&lt;h3 id="send-a-new-message-mid-stream" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;SEND A NEW MESSAGE MID-STREAM&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;There’s one more edge case that’s easy to miss. If the user sends a new message while a stream is still running, you end up with two loops writing to the DOM at the same time. The result is messy, and characters from different responses get mixed together.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Here’s what to do: stop the current stream before starting a new one.&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;function&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;startStream&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token parameter" style="box-sizing: border-box;"&gt;question&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; answer&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;if&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;isStreaming&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
    &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;clearTimeout&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;streamTimer&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
    isStreaming &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token boolean" style="box-sizing: border-box; color: #c92c2c;"&gt;false&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
    pending     &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;''&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
    rafQueued   &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token boolean" style="box-sizing: border-box; color: #c92c2c;"&gt;false&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
    &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;if&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;cursorEl &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cursorEl&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;parentNode&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; cursorEl&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;remove&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
    chat&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;removeEventListener&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'scroll'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; onScroll&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;

  &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// now reset and start fresh&lt;/span&gt;
  charIndex    &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token number" style="box-sizing: border-box; color: #c92c2c;"&gt;0&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  userScrolled &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token boolean" style="box-sizing: border-box; color: #c92c2c;"&gt;false&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  isStreaming  &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token boolean" style="box-sizing: border-box; color: #c92c2c;"&gt;true&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  lastQuestion &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; question&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// ...&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Here, we inline the cleanup rather than calling&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;stopStream&lt;/code&gt;&amp;nbsp;directly because&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;stopStream&lt;/code&gt;&amp;nbsp;also calls&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;markStopped&lt;/code&gt;&amp;nbsp;and resets the buttons. The next demo has all three behaviors wired up. You can start a stream, hit “Stop” mid-stream, and the cursor disappears, the “response stopped” label appears, and a “Retry” buttons displayed.&lt;/p&gt;&lt;figure style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 679.765625px;"&gt;&lt;a href="https://codesandbox.io/embed/9cfy92?view=preview" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="Interruptible stream" decoding="async" fetchpriority="low" height="505" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/5-interruptible-stream.png" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/5-interruptible-stream.png 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/5-interruptible-stream.png 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/5-interruptible-stream.png 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/5-interruptible-stream.png 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/5-interruptible-stream.png 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; padding: 0.75em 2em 0.75em 0px;"&gt;Open in&amp;nbsp;&lt;a href="https://codesandbox.io/embed/9cfy92?view=preview" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;CodeSandbox&lt;/a&gt;. (&lt;a href="https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/5-interruptible-stream.png" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;div aria-hidden="true" class="c-friskies-box partners partners__lead partners__lead-place partners__external" data-amount="1" data-audience="non-subscriber" data-remove="true" style="align-self: center; border-radius: 11px; box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 0.9em; grid-column-end: 13; grid-column-start: 3; margin: 3em auto 1em; position: relative; width: 679.765625px;"&gt;&lt;/div&gt;&lt;h2 id="accessibility" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Accessibility&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/designing-stable-interfaces-streaming-content/#accessibility" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Streaming interfaces are often built and tested with a mouse, so they may feel just fine in a browser, but break down in other situations that may not have been considered, like whether a screen reader announces new content at all. Or navigating with a keyboard might get stuck or lose focus as things update. And, of course, moving text can be uncomfortable — or even disabling — for&amp;nbsp;&lt;a href="https://www.smashingmagazine.com/2021/10/respecting-users-motion-preferences/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;those with motion sensitivities&lt;/a&gt;.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The good part is that you do not need to rebuild everything to accommodate these things; they can be fixed with solutions that sit on top of what is already there.&lt;/p&gt;&lt;h3 id="accommodating-assistive-technology-with-live-regions" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;ACCOMMODATING ASSISTIVE TECHNOLOGY WITH LIVE REGIONS&amp;nbsp;&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Screen readers don’t automatically announce content that shows up on its own. They usually read things when the user moves to them. So, in a streaming UI, where text builds up over time, nothing gets announced. The content is there, but the user doesn’t hear anything.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The fix is&amp;nbsp;&lt;a href="https://w3c.github.io/aria/#aria-live" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;aria-live&lt;/code&gt;&lt;/a&gt;. It tells the browser to watch a container and announce updates as they happen, without the user needing to move focus.&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-html" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-html" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token tag" style="box-sizing: border-box; color: #c92c2c;"&gt;&lt;span class="token tag" style="box-sizing: border-box;"&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt;
  &lt;span class="token attr-name" style="box-sizing: border-box; color: #2f9c0a;"&gt;id&lt;/span&gt;&lt;span class="token attr-value" style="box-sizing: border-box; color: #0e82a9;"&gt;&lt;span class="token punctuation attr-equals" style="box-sizing: border-box; color: #5f6364;"&gt;=&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;"&lt;/span&gt;chat&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;"&lt;/span&gt;&lt;/span&gt;
  &lt;span class="token attr-name" style="box-sizing: border-box; color: #2f9c0a;"&gt;role&lt;/span&gt;&lt;span class="token attr-value" style="box-sizing: border-box; color: #0e82a9;"&gt;&lt;span class="token punctuation attr-equals" style="box-sizing: border-box; color: #5f6364;"&gt;=&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;"&lt;/span&gt;log&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;"&lt;/span&gt;&lt;/span&gt;
  &lt;span class="token attr-name" style="box-sizing: border-box; color: #2f9c0a;"&gt;aria-live&lt;/span&gt;&lt;span class="token attr-value" style="box-sizing: border-box; color: #0e82a9;"&gt;&lt;span class="token punctuation attr-equals" style="box-sizing: border-box; color: #5f6364;"&gt;=&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;"&lt;/span&gt;polite&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;"&lt;/span&gt;&lt;/span&gt;
  &lt;span class="token attr-name" style="box-sizing: border-box; color: #2f9c0a;"&gt;aria-atomic&lt;/span&gt;&lt;span class="token attr-value" style="box-sizing: border-box; color: #0e82a9;"&gt;&lt;span class="token punctuation attr-equals" style="box-sizing: border-box; color: #5f6364;"&gt;=&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;"&lt;/span&gt;false&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;"&lt;/span&gt;&lt;/span&gt;
  &lt;span class="token attr-name" style="box-sizing: border-box; color: #2f9c0a;"&gt;aria-label&lt;/span&gt;&lt;span class="token attr-value" style="box-sizing: border-box; color: #0e82a9;"&gt;&lt;span class="token punctuation attr-equals" style="box-sizing: border-box; color: #5f6364;"&gt;=&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;"&lt;/span&gt;Chat messages&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;"&lt;/span&gt;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="token tag" style="box-sizing: border-box; color: #c92c2c;"&gt;&lt;span class="token tag" style="box-sizing: border-box;"&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;role="log"&lt;/code&gt;&amp;nbsp;tells assistive tech this is a stream of updates, like a running transcript. Some tools handle this automatically, but it’s safer to be explicit so behavior stays consistent.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;aria-atomic="false"&lt;/code&gt;&amp;nbsp;makes sure only the new content is announced. Without it, some screen readers try to read the whole message again on every update, which quickly becomes unusable.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;aria-live="polite"&lt;/code&gt;&amp;nbsp;queues updates instead of interrupting. Use&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;assertive&lt;/code&gt;&amp;nbsp;only for things that really need immediate attention, like errors.&lt;/li&gt;&lt;/ul&gt;&lt;h3 id="handling-incomplete-states" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;HANDLING INCOMPLETE STATES&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/designing-stable-interfaces-streaming-content/#handling-incomplete-states" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Earlier, we inserted a “Response Stopped” label to the message when the stream stops mid-stream. Visually, that’s enough. But for a screen reader, that change needs to be announced.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Since the message is inside a live region with&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;aria-live="polite"&lt;/code&gt;, the label will be automatically announced as new content when it’s added to the DOM. The live region already handles the announcement, so no additional ARIA is needed on the label itself.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Retry&lt;/span&gt;&amp;nbsp;button that appears next also needs context. If a screen reader simply says “Retry, button,” it’s not clear what action that refers to. You can fix that by adding an&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;aria-label&lt;/code&gt;&amp;nbsp;that includes the original question:&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;retryBtn&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;setAttribute&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;
  &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'aria-label'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt;
  &lt;span class="token template-string" style="box-sizing: border-box;"&gt;&lt;span class="token template-punctuation string" style="box-sizing: border-box; color: #2f9c0a;"&gt;`&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;Retry: &lt;/span&gt;&lt;span class="token interpolation" style="box-sizing: border-box;"&gt;&lt;span class="token interpolation-punctuation punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;${&lt;/span&gt;lastQuestion&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;slice&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token number" style="box-sizing: border-box; color: #c92c2c;"&gt;0&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; &lt;span class="token number" style="box-sizing: border-box; color: #c92c2c;"&gt;60&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token interpolation-punctuation punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="token template-punctuation string" style="box-sizing: border-box; color: #2f9c0a;"&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;What you can do here is to set this label when the button appears, not on page load:&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;retryBtn&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;style&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;display &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'inline-block'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
retryBtn&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;setAttribute&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;
  &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'aria-label'&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt;
  &lt;span class="token template-string" style="box-sizing: border-box;"&gt;&lt;span class="token template-punctuation string" style="box-sizing: border-box; color: #2f9c0a;"&gt;`&lt;/span&gt;&lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;Retry: &lt;/span&gt;&lt;span class="token interpolation" style="box-sizing: border-box;"&gt;&lt;span class="token interpolation-punctuation punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;${&lt;/span&gt;lastQuestion&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;slice&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token number" style="box-sizing: border-box; color: #c92c2c;"&gt;0&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;,&lt;/span&gt; &lt;span class="token number" style="box-sizing: border-box; color: #c92c2c;"&gt;60&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token interpolation-punctuation punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="token template-punctuation string" style="box-sizing: border-box; color: #2f9c0a;"&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;We also call&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;retryBtn.focus()&lt;/code&gt;&amp;nbsp;after stopping. That way, keyboard users don’t have to&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;Tab&lt;/code&gt;&amp;nbsp;around with the keyboard to find the next action.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Testing with assistive technology:&lt;/span&gt;&amp;nbsp;Don’t rely on assumptions about how screen readers announce this. Test with actual tools like NVDA (Windows), JAWS (Windows), or VoiceOver (Mac/iOS). Browser DevTools can show you what’s exposed in the accessibility tree, but they can’t tell you how the content&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;sounds&lt;/em&gt;. A real screen reader will reveal whether the announcement is happening at the right time and in the right way.&lt;/p&gt;&lt;h3 id="account-for-keyboard-navigation" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;ACCOUNT FOR KEYBOARD NAVIGATION&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/designing-stable-interfaces-streaming-content/#account-for-keyboard-navigation" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The controls need to work with the keyboard while the UI is live, so the Stop button has to be reachable. For someone not using a mouse,&amp;nbsp;&lt;kbd style="border-radius: 0.125rem; border: 1px solid rgb(211, 58, 44); box-shadow: rgb(211, 58, 44) 1px 1px, rgb(211, 58, 44) 2px 2px; box-sizing: border-box; color: #d33a2c; font-size: 0.9em; margin: 0px 0.25rem; padding: 0.0625rem 0.5rem;"&gt;Tab&lt;/kbd&gt;&amp;nbsp;+&amp;nbsp;&lt;kbd style="border-radius: 0.125rem; border: 1px solid rgb(211, 58, 44); box-shadow: rgb(211, 58, 44) 1px 1px, rgb(211, 58, 44) 2px 2px; box-sizing: border-box; color: #d33a2c; font-size: 0.9em; margin: 0px 0.25rem; padding: 0.0625rem 0.5rem;"&gt;Enter&lt;/kbd&gt;is the only way to cancel a running stream.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Using&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;display: none&lt;/code&gt;&amp;nbsp;is fine for hiding buttons; it removes them from the tab order. The problem is using things like&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;opacity: 0&lt;/code&gt;&amp;nbsp;or&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;visibility: hidden&lt;/code&gt;. Those hide elements visually, but they can still receive focus, so users end up tabbing onto something they can’t see.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Use&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;:focus-visible&lt;/code&gt;&amp;nbsp;so the focus ring shows up for keyboard navigation, but not for mouse clicks:&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-css" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-css" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token selector" style="box-sizing: border-box; color: #2f9c0a;"&gt;btn:focus-visible&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;outline&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; 2px solid #1d9e75&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;outline-offset&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; 2px&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The cursor inside the message should have&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;aria-hidden="true"&lt;/code&gt;. It’s just visual. Without that, some screen readers try to read it as text, which gets distracting.&lt;/p&gt;&lt;h3 id="motion-sensitivity" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;MOTION SENSITIVITY&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/designing-stable-interfaces-streaming-content/#motion-sensitivity" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The typewriter effect we see in practically every AI interface produces constant motion. As we’ve already discussed, certain amounts of motion can be disabling. Thankfully, browsers expose&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;prefers-reduced-motion&lt;/code&gt;, which detects a user’s motion preferences at the operating system level.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;For streaming, the best approach is simple: skip the animation and render the full response at once. The content stays the same, only without the motion.&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;const&lt;/span&gt; reducedMotion &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;=&lt;/span&gt; window&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;matchMedia&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;
  &lt;span class="token string" style="box-sizing: border-box; color: #2f9c0a;"&gt;'(prefers-reduced-motion: reduce)'&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;matches&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-javascript" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;if&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;reducedMotion&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;initAIMsg&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;for&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;const&lt;/span&gt; char &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;of&lt;/span&gt; text&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;appendChar&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;char&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;if&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;cursorEl &lt;span class="token operator" style="background: rgba(255, 255, 255, 0.5); box-sizing: border-box; color: #a67f59;"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cursorEl&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;parentNode&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt; cursorEl&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;.&lt;/span&gt;&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;remove&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;done&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
  &lt;span class="token keyword" style="box-sizing: border-box; color: #0e82a9;"&gt;return&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;span class="token function" style="box-sizing: border-box; color: #2f9c0a;"&gt;tick&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;text&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt; &lt;span class="token comment" style="box-sizing: border-box; color: #7d8b99;"&gt;// normal animation&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;In CSS, the cursor blink also needs to stop. Despite being a minor detail, a blinking cursor element counts as&amp;nbsp;&lt;a href="https://www.w3.org/WAI/WCAG21/Understanding/three-flashes-or-below-threshold.html" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;flashing content&lt;/a&gt;.&lt;/p&gt;&lt;div class="code-toolbar" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin-bottom: 0px; margin-top: 0px; position: relative;"&gt;&lt;pre class=" language-css" style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgb(245, 242, 240) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 11px; border: 1px solid rgb(238, 238, 238); box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -17px, rgba(0, 0, 0, 0.3) 0px 7px 6px -8px, rgba(0, 0, 0, 0.03) 0px -6px 16px -6px; box-sizing: border-box; color: #666666; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: 1em; font-variant-ligatures: none; hyphens: none; margin: 0.3em 0px 1.7em; max-width: 100vw; min-width: 250px; overflow-wrap: normal; overflow: auto; padding: 1rem; resize: both; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;&lt;code class=" language-css" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.75rem + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; white-space: break-spaces; word-break: normal; word-spacing: normal;"&gt;&lt;span class="token atrule" style="box-sizing: border-box; color: #0e82a9;"&gt;&lt;span class="token rule" style="box-sizing: border-box;"&gt;@media&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;(&lt;/span&gt;&lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;prefers-reduced-motion&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; reduce&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt;
  &lt;span class="token selector" style="box-sizing: border-box; color: #2f9c0a;"&gt;.cursor&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;{&lt;/span&gt; &lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;animation&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; none&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt; &lt;span class="token property" style="box-sizing: border-box; color: #c92c2c;"&gt;opacity&lt;/span&gt;&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;:&lt;/span&gt; 1&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;;&lt;/span&gt; &lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;span class="token punctuation" style="box-sizing: border-box; color: #5f6364;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="toolbar" style="box-sizing: border-box; opacity: 0; position: absolute; right: 0.5em; top: 0.5em; transition: opacity 0.3s ease-in-out;"&gt;&lt;div class="toolbar-item" style="background: rgb(255, 255, 255); border-radius: 11px; border: 1px solid rgb(221, 221, 221); box-shadow: rgb(222, 218, 218) 0px 4px; box-sizing: border-box; color: #267dcc; display: inline-block; font-family: Mija; font-size: 0.9em; font-weight: 700; outline: 0px; position: relative; text-align: center; text-shadow: none; top: -2px; transition: 0.3s ease-in-out;"&gt;&lt;button style="appearance: button; background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; border-color: currentcolor; border-style: none; border-width: 0px; cursor: pointer; font-family: inherit; font-feature-settings: inherit; font-kerning: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-size: inherit; font-style: inherit; font-variant-alternates: inherit; font-variant-caps: inherit; font-variant-east-asian: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-position: inherit; font-variation-settings: inherit; font-weight: inherit; font-width: inherit; margin: 0px; overflow: visible; padding: 0.75em 1.15em;" type="button"&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;There we go! The demo below puts everything from this article together, so you can see how these patterns work in practice. It also includes a reduced motion toggle, so you can test the instant render version easily.&lt;/p&gt;&lt;figure style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 679.765625px;"&gt;&lt;a href="https://codesandbox.io/embed/vd9mnk?view=preview" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="Accessible streaming" decoding="async" fetchpriority="low" height="594" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/6-accessible-streaming.png" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/6-accessible-streaming.png 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/6-accessible-streaming.png 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/6-accessible-streaming.png 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/6-accessible-streaming.png 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/6-accessible-streaming.png 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; padding: 0.75em 2em 0.75em 0px;"&gt;Open in&amp;nbsp;&lt;a href="https://codesandbox.io/embed/vd9mnk?view=preview" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;CodeSandbox&lt;/a&gt;. (&lt;a href="https://files.smashing.media/articles/designing-stable-interfaces-streaming-content/6-accessible-streaming.png" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;h2 id="conclusion" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Conclusion&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/designing-stable-interfaces-streaming-content/#conclusion" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Streaming itself is mostly solved. Getting data from the server to the client is not the hard part anymore. What breaks is the UI on top of it.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;When content updates continuously, small things start to matter, like scroll behavior, layout stability, render timing, and how the interface responds to user actions. If those aren’t handled well, the UI feels unstable and hard to use.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The patterns in this article fix that by:&lt;/p&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;Keeping scroll position under the user’s control,&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;Updating only what has changed,&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;Batching renders per frame,&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;Handling stop and retry actions, and&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;Making the interface accessible.&lt;/li&gt;&lt;/ul&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;You don’t need all of these every time. But when streaming is involved, these are the places things usually go wrong.&lt;/p&gt;&lt;h3 id="further-reading" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;FURTHER READING&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/05/designing-stable-interfaces-streaming-content/#further-reading" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Using Server-Sent Events&lt;/a&gt;&lt;br style="box-sizing: border-box;" /&gt;How to open a connection, handle events, and reconnect when needed. This is the transport layer, everything here builds on.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Streams_API" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Streams API&lt;/a&gt;&lt;br style="box-sizing: border-box;" /&gt;Streaming data directly from&amp;nbsp;&lt;code style="background: rgb(255, 242, 234); box-sizing: border-box; display: inline-block; font-family: &amp;quot;Fira Code&amp;quot;, Menlo, Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; font-feature-settings: normal; font-size: calc(0.75em + 0.1vw); font-variant-ligatures: none; hyphens: none; line-height: calc(1.5em + 0.2vw); overflow-wrap: normal; padding: 0px 0.2725em; tab-size: 4; text-shadow: rgb(255, 255, 255) 0px 1px; word-break: normal; word-spacing: normal;"&gt;fetch&lt;/code&gt;. Useful when you need more control than SSE.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://developer.chrome.com/docs/devtools/performance" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Chrome DevTools Performance panel&lt;/a&gt;&lt;br style="box-sizing: border-box;" /&gt;Helps you see layout recalculations and paint costs, so you can verify performance improvements.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;“&lt;a href="https://web.dev/articles/dom-size-and-interactivity" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;How Large DOM Sizes Affect Interactivity, And What You Can Do About It&lt;/a&gt;”, Jeremy Wagner&lt;br style="box-sizing: border-box;" /&gt;Why large DOM trees slow things down, and how to keep them under control in long streaming sessions.&lt;/li&gt;&lt;/ul&gt;</description><link>http://honeyvig.blogspot.com/2026/06/designing-stable-interfaces-for.html</link><author>noreply@blogger.com (H)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-9165069509664255576.post-7057580669020309933</guid><pubDate>Mon, 01 Jun 2026 14:51:41 +0000</pubDate><atom:updated>2026-06-01T07:51:41.451-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">AI</category><category domain="http://www.blogger.com/atom/ns#">Business</category><category domain="http://www.blogger.com/atom/ns#">Workflow</category><title>The “Bug-Free” Workforce: How AI Efficiency Is Subtly Disrupting The Interactions That Build Strong Teams</title><description>&lt;p&gt;&amp;nbsp;&lt;span style="caret-color: rgb(51, 51, 51); color: #666666; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 1.15em; font-style: italic;"&gt;AI tools are eliminating the need to “bug” colleagues for help, but the informal interactions they replace are the very scaffolding that builds team trust, belonging, and innovation. Here explore the research and potential impacts behind that risk and offer practical strategies for maintaining human connection while leveraging AI’s strengths.&lt;/span&gt;&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 1.1em; grid-column-end: 13; grid-column-start: 3; line-height: 1.55em; margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Through many discussions with industry colleagues, we’ve started hearing a phrase more often when swapping stories about AI adoption:&lt;/p&gt;&lt;blockquote style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgba(245, 242, 240, 0.89) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-left-color: rgb(230, 228, 225); border-left-style: solid; border-left-width: 11px; border-radius: 11px; box-sizing: border-box; color: #424242; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 1.05em; font-style: italic; grid-column-end: 13; grid-column-start: 3; line-height: 1.65em; margin: 0.3em 0px 1.7em; padding: 1em calc(1.5em + 0.5vw);"&gt;“Now I don’t have to&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;bug&lt;/span&gt;&amp;nbsp;[someone].”&lt;/blockquote&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Product designers don’t need to bug researchers anymore — retrieval-augment generation (RAG) tools surface insights instantly. Product Managers don’t need to&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;bug&lt;/em&gt;&amp;nbsp;designers for mockups — AI generates acceptable options. Engineers don’t need to&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;bug&lt;/em&gt;&amp;nbsp;accessibility teams — automated scanners flag issues in real-time.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;It’s framed as liberation, and in many ways, it is. There’s genuine relief in being unblocked, in not having to wait, in solving problems independently.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;With AI, we’re building a “bug-free workforce”.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;But what if the bugs that AI is automating away, such as the quick questions, the small talk, the organic connections, are actually an important part of the scaffolding that builds and sustains healthy teams?&lt;/p&gt;&lt;h2 id="the-vanishing-scaffolding" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;The Vanishing Scaffolding&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Consider what actually disappears when we turn to AI assistance before engaging with a colleague directly. For instance:&lt;/p&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;The 2-minute Slack exchange that turns into a 20-minute whiteboarding session.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;The “quick question” that reveals a fundamental misalignment.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;The accessibility review that becomes mentorship.&lt;/li&gt;&lt;/ul&gt;&lt;figure class="break-out article__image" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 14; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 774.9375px;"&gt;&lt;a href="https://files.smashing.media/articles/bug-free-workforce/1-ai-driven-efficiency-weaken-team-cohesion.jpg" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="Two diagrams comparing teamwork: a dense, interconnected human network vs a centralized AI-driven network that is efficient but isolates individuals" decoding="async" fetchpriority="low" height="450" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/bug-free-workforce/1-ai-driven-efficiency-weaken-team-cohesion.jpg" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/bug-free-workforce/1-ai-driven-efficiency-weaken-team-cohesion.jpg 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/bug-free-workforce/1-ai-driven-efficiency-weaken-team-cohesion.jpg 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/bug-free-workforce/1-ai-driven-efficiency-weaken-team-cohesion.jpg 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/bug-free-workforce/1-ai-driven-efficiency-weaken-team-cohesion.jpg 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/bug-free-workforce/1-ai-driven-efficiency-weaken-team-cohesion.jpg 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; max-width: 50em; padding: 0.75em 2em 0.75em 0px;"&gt;AI-driven efficiency can weaken team cohesion. (&lt;a href="https://files.smashing.media/articles/bug-free-workforce/1-ai-driven-efficiency-weaken-team-cohesion.jpg" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Although these interactions are primarily intended to exchange information and unblock individuals’ tasks, many are the building blocks for the intangible but crucial sense of belonging and connection in the workplace.&lt;/p&gt;&lt;blockquote style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgba(245, 242, 240, 0.89) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-left-color: rgb(230, 228, 225); border-left-style: solid; border-left-width: 11px; border-radius: 11px; box-sizing: border-box; color: #424242; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 1.05em; font-style: italic; grid-column-end: 13; grid-column-start: 3; line-height: 1.65em; margin: 0.3em 0px 1.7em; padding: 1em calc(1.5em + 0.5vw);"&gt;The inefficiencies of interpersonal communication and daily interaction build the larger organism known as work culture. When AI disrupts these interactions, what is lost?&lt;/blockquote&gt;&lt;h2 id="what-the-research-actually-shows" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;What The Research Actually Shows&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;There is ample psychological research to support our hypothesis: If the trust built through organic and informal connections is threatened, teams will be negatively impacted. Let’s examine a few:&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;In 2012,&amp;nbsp;&lt;a href="https://hbr.org/2012/04/the-new-science-of-building-great-teams" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;MIT’s Human Dynamics Lab (Pentland, 2012)&lt;/a&gt;&amp;nbsp;discovered that the best predictor of team productivity wasn’t formal meetings but “energy” from informal communication: the hallway conversations, coffee chats, and quick questions. Teams with the most informal interaction had&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;35% more successful outcomes&lt;/span&gt;. With AI, what energy is&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;not&lt;/em&gt;&amp;nbsp;generated, leading to fewer successful outcomes?&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;In 2015,&amp;nbsp;&lt;a href="https://www.nytimes.com/2016/02/28/magazine/what-google-learned-from-its-quest-to-build-the-perfect-team.html?unlocked_article_code=1.W1A.sA1C.ptegMsaJ_EY0&amp;amp;smid=url-share" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Google’s Project Aristotle&lt;/a&gt;&amp;nbsp;studied over 180 teams to find out why some thrived, and others underperformed. They found that psychological safety, the shared belief among team members that the environment is safe for interpersonal risk-taking, built through frequent, low-stakes interactions, was the&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;number one predictor of high performance&lt;/span&gt;. Not intelligence. Not resources. Trust built through&amp;nbsp;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;micro-moments&lt;/span&gt;. The exact micro-moments we see vanishing when we overuse AI.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;In 2025, researchers from Harvard, Columbia, and Yeshiva University published&amp;nbsp;&lt;a href="https://direct.mit.edu/rest/article/107/4/951/115633/Super-Mario-Meets-AI-Experimental-Effects-of" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;a study focused on the impact of AI on performance and team coordination&lt;/a&gt;. The authors concluded that AI-driven automation decreased overall team performance and increased coordination failures. These effects were especially large in the short-term and in low- and medium-skilled teams. Automation also decreased team trust.&lt;/p&gt;&lt;h2 id="why-this-matters" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Why This Matters&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;When AI disrupts the team’s energy and psychological safety, a sense of disconnection sets in, which, in turn, hurts the company’s bottom line.&lt;/p&gt;&lt;figure class="break-out article__image" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 14; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 774.9375px;"&gt;&lt;a href="https://files.smashing.media/articles/bug-free-workforce/2-ai-disrupts-team-energy.jpg" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="Central worker connected to an AI system, with weaker, fading links to other people" decoding="async" fetchpriority="low" height="450" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/bug-free-workforce/2-ai-disrupts-team-energy.jpg" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/bug-free-workforce/2-ai-disrupts-team-energy.jpg 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/bug-free-workforce/2-ai-disrupts-team-energy.jpg 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/bug-free-workforce/2-ai-disrupts-team-energy.jpg 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/bug-free-workforce/2-ai-disrupts-team-energy.jpg 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/bug-free-workforce/2-ai-disrupts-team-energy.jpg 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; max-width: 50em; padding: 0.75em 2em 0.75em 0px;"&gt;Adding AI to the team increases efficiency, but also risks displacing the human-to-human connections that establish psychological safety. (&lt;a href="https://files.smashing.media/articles/bug-free-workforce/2-ai-disrupts-team-energy.jpg" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;h3 id="disconnected-employees-leave" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;DISCONNECTED EMPLOYEES LEAVE&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;People don’t stay at companies because of the work. They stay because of the people. And if connections to colleagues decrease due to AI’s presence, how might that expedite one’s departure?&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Consider this question in dollar terms. McKinsey’s&amp;nbsp;&lt;a href="https://www.mckinsey.com/capabilities/people-and-organizational-performance/our-insights/the-organization-blog/the-great-attrition-the-power-of-adaptability" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Great Attrition research&lt;/a&gt;&amp;nbsp;found that not feeling a sense of belonging was one of the most frequently cited reasons employees left. When informal micro-interactions disappear, belonging erodes, and people walk.&lt;/p&gt;&lt;blockquote style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgba(245, 242, 240, 0.89) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-left-color: rgb(230, 228, 225); border-left-style: solid; border-left-width: 11px; border-radius: 11px; box-sizing: border-box; color: #424242; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 1.05em; font-style: italic; grid-column-end: 13; grid-column-start: 3; line-height: 1.65em; margin: 0.3em 0px 1.7em; padding: 1em calc(1.5em + 0.5vw);"&gt;“Employee disengagement and attrition could cost a median-size S&amp;amp;P 500 company between $228 million and $355 million a year in lost productivity.”&lt;br style="box-sizing: border-box;" /&gt;&lt;br style="box-sizing: border-box;" /&gt;—&amp;nbsp;&lt;a href="https://www.mckinsey.com/capabilities/people-and-organizational-performance/our-insights/some-employees-are-destroying-value-others-are-building-it-do-you-know-the-difference" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;McKinsey&lt;/a&gt;&lt;/blockquote&gt;&lt;figure class="break-out article__image" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 14; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 774.9375px;"&gt;&lt;a href="https://files.smashing.media/articles/bug-free-workforce/3-cost-employee-disengagement.png" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="Chart showing employee disengagement and attrition costs rising from $228M to $355M annually in a higher-attrition scenario" decoding="async" fetchpriority="low" height="497" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/bug-free-workforce/3-cost-employee-disengagement.png" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/bug-free-workforce/3-cost-employee-disengagement.png 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/bug-free-workforce/3-cost-employee-disengagement.png 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/bug-free-workforce/3-cost-employee-disengagement.png 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/bug-free-workforce/3-cost-employee-disengagement.png 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/bug-free-workforce/3-cost-employee-disengagement.png 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; max-width: 50em; padding: 0.75em 2em 0.75em 0px;"&gt;The hidden but real cost of employee disengagement and attrition from&amp;nbsp;&lt;a href="https://www.mckinsey.com/capabilities/people-and-organizational-performance/our-insights/some-employees-are-destroying-value-others-are-building-it-do-you-know-the-difference" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;McKinsey&lt;/a&gt;. (&lt;a href="https://files.smashing.media/articles/bug-free-workforce/3-cost-employee-disengagement.png" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Leaders must ask themselves if the potential gains from AI rollouts and promised productivity gains outweigh the costs of a disengaged and attrition-prone workforce. The evidence suggests otherwise.&lt;/p&gt;&lt;h3 id="disconnected-teams-are-less-innovative" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;DISCONNECTED TEAMS ARE LESS INNOVATIVE&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Korean researchers in 2024&amp;nbsp;&lt;a href="https://compass.onlinelibrary.wiley.com/doi/10.1111/soc4.13214" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;analyzed innovation in the private sector&lt;/a&gt;&amp;nbsp;and concluded that weak ties — the bridging conversations with people you interact with occasionally — sustained innovative performance in companies characterized by active technological innovation.&lt;/p&gt;&lt;div aria-hidden="true" class="c-friskies-box partners partners__lead partners__lead-place partners__external" data-amount="1" data-audience="non-subscriber" data-remove="true" data-rendered="true" style="align-self: center; border-radius: 11px; box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 0.9em; grid-column-end: 13; grid-column-start: 3; margin: 3em auto 1em; position: relative; width: 679.765625px;"&gt;&lt;ul style="box-sizing: border-box; list-style: outside; margin: 1em 0px 1.4em; max-width: 100%; padding-left: 0px; text-align: center;"&gt;&lt;a class="partners__native--smashing" href="https://www.smashingmagazine.com/contact/" style="border-radius: 11px; box-shadow: none; box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; transition: box-shadow 0.2s ease-in-out, top 0.1s ease-in-out;"&gt;&lt;picture style="box-sizing: border-box;"&gt;&lt;source media="(max-width: 600px)" srcset="https://www.smashingmagazine.com/images/banners/smashing-friskies-300x250.png" style="box-sizing: border-box;"&gt;&lt;/source&gt;&lt;img alt="Advertise with Smashing Magazine" decoding="async" fetchpriority="low" loading="lazy" srcset="https://www.smashingmagazine.com/images/banners/smashing-friskies-300x250.svg" style="border-style: none; box-sizing: border-box; max-width: 100%; position: relative;" width="325" /&gt;&lt;/picture&gt;&lt;/a&gt;&lt;/ul&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Simply put, breakthroughs do not necessarily emerge from your core team but from interactions with the people you would have “bugged” in the past. Eliminating these interactions in favor of AI could not only negatively impact team health, but it could also hurt the business through decreased depth and breadth of innovation in design, coding, content, and beyond.&lt;/p&gt;&lt;blockquote style="background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(to right bottom, rgba(245, 242, 240, 0.89) 0px, rgb(255, 255, 255) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-left-color: rgb(230, 228, 225); border-left-style: solid; border-left-width: 11px; border-radius: 11px; box-sizing: border-box; color: #424242; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 1.05em; font-style: italic; grid-column-end: 13; grid-column-start: 3; line-height: 1.65em; margin: 0.3em 0px 1.7em; padding: 1em calc(1.5em + 0.5vw);"&gt;AI’s seduction is that it feels like pure gain until the team realizes they’ve become strangers who happen to work on the same project.&lt;/blockquote&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;If a shared sense of purpose and belonging disappears, employers have a workforce less engaged and less innovative, with a higher chance of attrition.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;If AI helps us need each other less, how can a company hope to nurture a connected, supported, and effective workforce?&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;The answer requires a balanced and multi-pronged approach. Use AI tools for dull, repetitive, and high-volume tasks while reserving the human brain for higher-level problem solving. Design physical workspaces and online team interactions that will maintain or increase human connection.&lt;/p&gt;&lt;h2 id="maintaining-the-best-of-both" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Maintaining The Best Of Both&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;In short, leverage the best of AI tools and human abilities.&lt;/p&gt;&lt;h3 id="1-use-ai-to-eliminate-the-toil" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;1. USE AI TO ELIMINATE THE TOIL&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;In the March 2026 article “&lt;a href="https://hbr.org/2026/03/when-using-ai-leads-to-brain-fry" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;When Using AI Leads to ‘Brain Fry’&lt;/a&gt;,” the authors outline their study of 1,488 full-time U.S.-based workers to understand the impact of AI use on professionals. The result was a concept they call “AI Brain Fry,” a form of acute mental fatigue and cognitive exhaustion resulting from excessive use, interaction, or oversight of AI tools beyond an individual’s cognitive capacity.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Further, the study reveals that the cognitive strain created by intensive AI use carries business costs, including decision fatigue and error-prone work. Perhaps the most troubling finding is that 34% of workers who reported experiencing brain fry intended to quit their jobs. The loss of institutional knowledge caused by turnover is well documented.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;One conclusion is that AI is not inherently bad or cognitively taxing. Rather, as with any tool, what matters is how it’s used.&lt;/p&gt;&lt;blockquote class="pull-quote" style="box-sizing: border-box; color: #222222; font-family: Mija; font-size: 32px; font-weight: 700; grid-column-end: 13; grid-column-start: 3; letter-spacing: -0.75px; margin: 1.4em 0px; padding-left: 2.5em; position: relative;"&gt;&lt;p style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0px; margin-top: 0px; word-break: break-word;"&gt;&lt;a aria-label="Share on Twitter" class="pull-quote__link" href="https://twitter.com/share?text=%0aFocusing%20our%20energy%20on%20identifying%20the%20repetitive,%20unenjoyable%20parts%20of%20our%20jobs%20%28or%20%e2%80%9ctoil%e2%80%9d%29%20and%20using%20AI%20to%20remove%20them%20is%20a%20way%20to%20improve%20cognitive%20and%20team%20health.%0a&amp;amp;url=https://smashingmagazine.com%2f2026%2f04%2fbug-free-workforce-ai-disrupting-teams%2f" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: block; font-size: 1em; line-height: 42px; padding: 0px; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px;"&gt;Focusing our energy on identifying the repetitive, unenjoyable parts of our jobs (or “toil”) and using AI to remove them is a way to improve cognitive and team health.&lt;/a&gt;&lt;/p&gt;&lt;div class="pull-quote__quotation" style="box-sizing: border-box; left: 0px; position: absolute; top: 5px; width: 2em;"&gt;&lt;div class="pull-quote__bg" style="background: rgb(211, 58, 44); border-radius: 11px; box-sizing: border-box; height: 2em; padding-top: 0.15em; text-align: center; transform-origin: left bottom; transform: scale(1) rotateZ(-11deg); transition: transform 0.3s ease-out; width: 2em;"&gt;&lt;span class="pull-quote__symbol" style="box-sizing: border-box; color: white; display: block; font-size: 2.75em; line-height: 1em; transform: rotate(11deg) translateY(5px) translateX(-4px);"&gt;“&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Indeed, the Harvard Business Review authors explain that participants in their study who used AI to eliminate toil only had 15% lower rates of burnout but also reported&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;“a higher degree of social connection with peers…because they had more time to spend ‘off keyboard.’”&lt;/em&gt;&amp;nbsp;In this toil-elimination scenario, AI did not disrupt team connections; it removed what we consider busy work that prevented the team from solving problems with colleagues.&lt;/p&gt;&lt;h3 id="2-institutionalize-productive-friction" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;2. INSTITUTIONALIZE PRODUCTIVE FRICTION&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/04/bug-free-workforce-ai-disrupting-teams/#2-institutionalize-productive-friction" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Steve Jobs famously designed the Pixar studios so employees would have to bump into each other.&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;“Steve realized that when people run into each other, when they make eye contact, things happen,”&lt;/em&gt;&amp;nbsp;&lt;a href="https://officesnapshots.com/2012/07/16/pixar-headquarters-and-the-legacy-of-steve-jobs/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;reflected Brad Bird&lt;/a&gt;, the director of&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;The Incredibles&lt;/em&gt;and&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;Ratatouille&lt;/em&gt;&amp;nbsp;movies. John Lasseter, responsible for some of Pixar’s most beloved films, shared that he’d&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;“never seen a building that promoted collaboration and creativity as well as this one.”&lt;/em&gt;&amp;nbsp;Jobs understood that serendipitous collision drives creative work, and Pixar’s oeuvre reveals the genius.&lt;/p&gt;&lt;figure class="break-out article__image" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 14; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 774.9375px;"&gt;&lt;a href="https://files.smashing.media/articles/bug-free-workforce/4-pixar-studio-floor-plans.png" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="Pixar Studio’s floor plans, which facilitate face-to-face interaction" decoding="async" fetchpriority="low" height="450" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/bug-free-workforce/4-pixar-studio-floor-plans.png" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/bug-free-workforce/4-pixar-studio-floor-plans.png 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/bug-free-workforce/4-pixar-studio-floor-plans.png 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/bug-free-workforce/4-pixar-studio-floor-plans.png 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/bug-free-workforce/4-pixar-studio-floor-plans.png 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/bug-free-workforce/4-pixar-studio-floor-plans.png 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; max-width: 50em; padding: 0.75em 2em 0.75em 0px;"&gt;Pixar Studio’s floor plans facilitated face-to-face interaction. (&lt;a href="https://files.smashing.media/articles/bug-free-workforce/4-pixar-studio-floor-plans.png" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;div aria-hidden="true" class="c-friskies-box partners partners__lead partners__lead-place partners__external" data-amount="1" data-audience="non-subscriber" data-remove="true" style="align-self: center; border-radius: 11px; box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 0.9em; grid-column-end: 13; grid-column-start: 3; margin: 3em auto 1em; position: relative; width: 679.765625px;"&gt;&lt;/div&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;What is the equivalent of creating this type of organizational design in the age of AI?&lt;/p&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Build AI tools that connect the team.&lt;/span&gt;&lt;br style="box-sizing: border-box;" /&gt;We’ve found that when building internal agents, it’s best to attach the names of the original creators to the work and to direct seekers to these creators. This way, any seeker not only finds the answer but is connected to others with more institutional knowledge to help.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Publicly spotlight successful team uses of AI.&lt;/span&gt;&lt;br style="box-sizing: border-box;" /&gt;By finding examples of how teams have used AI to work more effectively and efficiently&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;together&lt;/em&gt;&amp;nbsp;and highlighting them in public forums and townhalls, it helps establish the narrative that AI can be something that brings us together rather than pushes us apart.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Establish rotation programs.&lt;/span&gt;&lt;br style="box-sizing: border-box;" /&gt;If AI means product managers can prototype, have them shadow designers anyway. Having a more holistic understanding of each other’s craft through direct dialogues benefits both sides beyond simple AI outputs.&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Hold panel discussions on the evolution of work.&lt;/span&gt;&lt;br style="box-sizing: border-box;" /&gt;Gather cross-functional partners to regularly discuss and debate how our work is currently changing or could in the near future. It keeps&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;intentional&lt;/em&gt;change top of mind and in the open.&lt;/li&gt;&lt;/ul&gt;&lt;h3 id="3-build-team-cohesion-through-ai-inspired-laughter" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;3. BUILD TEAM COHESION THROUGH AI-INSPIRED LAUGHTER&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/04/bug-free-workforce-ai-disrupting-teams/#3-build-team-cohesion-through-ai-inspired-laughter" style="box-sizing: border-box; color: #767676; padding: 0.35em 0.05em; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px; transition: color 0.2s ease-in-out;"&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Positive humor in the workplace has been&amp;nbsp;&lt;a href="https://www.humorseriously.com/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;studied extensively&lt;/a&gt;&amp;nbsp;as a way for teams to bond. We see how AI can improve team connections through a good, absurd laugh.&lt;/p&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Bad UX Vibecoding Competitions&lt;/span&gt;&lt;br style="box-sizing: border-box;" /&gt;Give your team a silly prompt (“Design the worst volume control”) and 30 minutes to vibe-code a horrible solution. The process of building these outputs helps the team: learn new AI tools, get the creative juices flowing, and, most importantly, laugh together.&lt;/li&gt;&lt;/ul&gt;&lt;figure class="break-out article__image" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 14; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 774.9375px;"&gt;&lt;a href="https://files.smashing.media/articles/bug-free-workforce/5-results-vibe-coding-activity.png" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="The results of a silly vibe-coding activity the team used to learn and stay connected" decoding="async" fetchpriority="low" height="628" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/bug-free-workforce/5-results-vibe-coding-activity.png" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/bug-free-workforce/5-results-vibe-coding-activity.png 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/bug-free-workforce/5-results-vibe-coding-activity.png 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/bug-free-workforce/5-results-vibe-coding-activity.png 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/bug-free-workforce/5-results-vibe-coding-activity.png 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/bug-free-workforce/5-results-vibe-coding-activity.png 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; max-width: 50em; padding: 0.75em 2em 0.75em 0px;"&gt;The results of a silly vibe-coding activity our team used to learn and stay connected (built with Google Gemini). (&lt;a href="https://files.smashing.media/articles/bug-free-workforce/5-results-vibe-coding-activity.png" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;span style="box-sizing: border-box; letter-spacing: 0px;"&gt;Hyper-specific AI Creations&lt;/span&gt;&lt;br style="box-sizing: border-box;" /&gt;Would a certain image make people smile in this workshop? Is there a funny idea at work that would be even weirder as an AI-generated song? Using them for absurd work moments is a fun way to get people laughing.&lt;/li&gt;&lt;/ul&gt;&lt;figure class="break-out article__image" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 14; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 774.9375px;"&gt;&lt;a href="https://files.smashing.media/articles/bug-free-workforce/6-ai-spin-cliche.png" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="AI-created spin on a cliche: you can lead a horse to water, but you can't make it prompt" decoding="async" fetchpriority="low" height="436" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/bug-free-workforce/6-ai-spin-cliche.png" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/bug-free-workforce/6-ai-spin-cliche.png 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/bug-free-workforce/6-ai-spin-cliche.png 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/bug-free-workforce/6-ai-spin-cliche.png 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/bug-free-workforce/6-ai-spin-cliche.png 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/bug-free-workforce/6-ai-spin-cliche.png 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; max-width: 50em; padding: 0.75em 2em 0.75em 0px;"&gt;Use AI to create a spin on a cliche for a laugh or icebreaker for a workshop or team meeting (made with Google Gemini). (&lt;a href="https://files.smashing.media/articles/bug-free-workforce/6-ai-spin-cliche.png" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Eliminating toil, institutionalizing productive friction, and building team cohesion through humor show the power of integrating the best of the human brain and AI algorithms.&lt;/p&gt;&lt;figure class="break-out article__image" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 14; grid-column-start: 3; margin: 0px auto 1.4em; padding: 0px; width: 774.9375px;"&gt;&lt;a href="https://files.smashing.media/articles/bug-free-workforce/7-combination-ai-human-driven-activity.jpg" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #006fc6; display: block; padding: 7px 0px; position: relative; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px; z-index: 99;"&gt;&lt;img alt="Three diagrams comparing teamwork: a dense, interconnected human network vs a centralized AI-driven network that is efficient but isolates individuals vs an interconnected human network with AI in the middle." decoding="async" fetchpriority="low" height="450" loading="lazy" sizes="100vw" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/bug-free-workforce/7-combination-ai-human-driven-activity.jpg" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/bug-free-workforce/7-combination-ai-human-driven-activity.jpg 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/bug-free-workforce/7-combination-ai-human-driven-activity.jpg 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/bug-free-workforce/7-combination-ai-human-driven-activity.jpg 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/bug-free-workforce/7-combination-ai-human-driven-activity.jpg 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/bug-free-workforce/7-combination-ai-human-driven-activity.jpg 2000w" style="border-style: none; box-sizing: border-box; display: block; height: auto; margin: 0px auto; max-width: 100%; position: relative; width: auto;" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom" style="box-sizing: border-box; color: #666666; display: table; font-size: 0.95em; font-style: italic; margin: 0px auto; max-width: 50em; padding: 0.75em 2em 0.75em 0px;"&gt;The right combination of AI and human-driven activity increases efficiency while training human connection. (&lt;a href="https://files.smashing.media/articles/bug-free-workforce/7-combination-ai-human-driven-activity.jpg" style="box-sizing: border-box; color: #666666; padding: 7px 0px; text-decoration-color: currentcolor; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;blockquote class="pull-quote" style="box-sizing: border-box; color: #222222; font-family: Mija; font-size: 32px; font-weight: 700; grid-column-end: 13; grid-column-start: 3; letter-spacing: -0.75px; margin: 1.4em 0px; padding-left: 2.5em; position: relative;"&gt;&lt;p style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0px; margin-top: 0px; word-break: break-word;"&gt;&lt;a aria-label="Share on Twitter" class="pull-quote__link" href="https://twitter.com/share?text=%0aThe%20question%20isn%e2%80%99t%20whether%20to%20use%20AI.%20Contemporary%20workers%20have%20less%20and%20less%20choice.%20The%20question%20is:%20what%20kind%20of%20team%20do%20you%20want%20to%20become%20when%20AI%20is%20the%20newest%20teammate?%0a&amp;amp;url=https://smashingmagazine.com%2f2026%2f04%2fbug-free-workforce-ai-disrupting-teams%2f" style="background-attachment: scroll; background-clip: border-box; background-image: none; background-origin: padding-box; background-position: 0px 0px; background-repeat: repeat; background-size: auto; box-sizing: border-box; color: #333333; display: block; font-size: 1em; line-height: 42px; padding: 0px; text-decoration-skip-ink: auto; text-decoration: none; text-underline-offset: 1px;"&gt;The question isn’t whether to use AI. Contemporary workers have less and less choice. The question is: what kind of team do you want to become when AI is the newest teammate?&lt;/a&gt;&lt;/p&gt;&lt;div class="pull-quote__quotation" style="box-sizing: border-box; left: 0px; position: absolute; top: 5px; width: 2em;"&gt;&lt;div class="pull-quote__bg" style="background: rgb(211, 58, 44); border-radius: 11px; box-sizing: border-box; height: 2em; padding-top: 0.15em; text-align: center; transform-origin: left bottom; transform: scale(1) rotateZ(-11deg); transition: transform 0.3s ease-out; width: 2em;"&gt;&lt;span class="pull-quote__symbol" style="box-sizing: border-box; color: white; display: block; font-size: 2.75em; line-height: 1em; transform: rotate(11deg) translateY(5px) translateX(-4px);"&gt;“&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;h2 id="conclusion" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.5rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; margin: 1.5em 0px 1em; position: relative; text-transform: capitalize;"&gt;Conclusion&lt;/h2&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;Leaders who introduce artificial intelligence with an equal amount of&amp;nbsp;&lt;em style="box-sizing: border-box;"&gt;emotional intelligence&lt;/em&gt;&amp;nbsp;will enable their teams to thrive by leveraging the power of AI while also shielding their teams from the inherent risks associated with the disruptive natures of these new tools.&lt;/p&gt;&lt;p style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; line-height: calc(1.5em + 0.2vw); margin-bottom: 1.4em; margin-top: 0px; word-break: break-word;"&gt;When the unexpected hits — the crisis, the pivot, the moment that requires trust you can’t manufacture overnight — it will be the teams with cultures intact that will thrive.&lt;/p&gt;&lt;h3 id="references" style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: calc(1.125rem + 0.25vw); grid-column-end: 13; grid-column-start: 3; letter-spacing: 1px; margin-bottom: 0.65em; margin-top: 1.5em; position: relative; text-transform: uppercase;"&gt;REFERENCES&lt;/h3&gt;&lt;ul style="box-sizing: border-box; caret-color: rgb(51, 51, 51); color: #333333; font-family: Elena, -apple-system, BlinkMacSystemFont, Roboto, &amp;quot;roboto slab&amp;quot;, &amp;quot;droid serif&amp;quot;, &amp;quot;segoe ui&amp;quot;, system-ui, Arial, sans-serif; font-size: 20.297499px; grid-column-end: 13; grid-column-start: 3; list-style: outside; margin: 0px 0px 1.4em; max-width: 100%;"&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://www.amazon.com/Stages-Psychological-Safety-Inclusion-Innovation/dp/0369356551?adgrpid=180038482722&amp;amp;hvpone=&amp;amp;hvptwo=&amp;amp;hvadid=748008426882&amp;amp;hvpos=&amp;amp;hvnetw=g&amp;amp;hvrand=18293123324910416997&amp;amp;hvqmt=&amp;amp;hvdev=c&amp;amp;hvdvcmdl=&amp;amp;hvlocint=&amp;amp;hvlocphy=9018945&amp;amp;hvtargid=dsa-2414841787086&amp;amp;hydadcr=&amp;amp;mcid=&amp;amp;hvocijid=18293123324910416997--&amp;amp;hvexpln=m-dsad&amp;amp;tag=googhydr-20&amp;amp;hvsb=Money_d&amp;amp;hvcampaign=dsadesk" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;The 4 Stages of Psychological Safety: Defining the Path to Inclusion and Innovation&lt;/a&gt;, Clark, T. R. (2020), Berrett-Koehler Publishers&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://www.nytimes.com/2016/02/28/magazine/what-google-learned-from-its-quest-to-build-the-perfect-team.html" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;What Google Learned From Its Quest to Build the Perfect Team&lt;/a&gt;, Duhigg, C. (2016), The New York Times Magazine&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://www.hbs.edu/faculty/Pages/item.aspx?num=2959" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Psychological Safety and Learning Behavior in Work Teams&lt;/a&gt;, Edmondson, A. C. (1999), Administrative Science Quarterly, 44(2)&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://compass.onlinelibrary.wiley.com/doi/10.1111/soc4.13214" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;The Strength of a Weak Tie in the Innovative Performance of Firms: A Case of Korean High-tech Manufacturing Small and Medium-sized Enterprises&lt;/a&gt;, Hong, Jinki; Lee; Raehyung; Ohm, Jay Y.;, Lee, Duk Hee (2024), Sociology Compass Volume 18, Issue 5&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://www.tandfonline.com/doi/abs/10.1080/08956308.2021.1863111" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;How Psychological Safety Impacts R&amp;amp;D Project Teams&lt;/a&gt;, Liu, Yuwen; Keller, R.T. (2021), Research-Technology Management Volume 64, Issue 2&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://www.tandfonline.com/doi/full/10.1080/08956308.2023.2164439" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Creating Psychological Safety in the Workplace&lt;/a&gt;, McCausland, Tammy (2023), Research-Technology Management Volume 66, Issue 2&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://www.mckinsey.com/capabilities/people-and-organizational-performance/our-insights/some-employees-are-destroying-value-others-are-building-it-do-you-know-the-difference" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Some Employees Are Destroying Value. Others Are Building It. Do You Know the Difference?&lt;/a&gt;, De Smet, Aaron; Mugayar-Baldocchi, Marino; Reich, Angelika; Schaninger, Bill (September 11, 2023), McKinsey Quarterly&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://hbr.org/2012/04/the-new-science-of-building-great-teams" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;The New Science of Building Great Teams&lt;/a&gt;, Pentland, A. (2012), Harvard Business Review&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://direct.mit.edu/rest/article/107/4/951/115633/Super-Mario-Meets-AI-Experimental-Effects-of" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Super Mario Meets AI: Experimental Effects of Automation and Skills on Team Performance and Coordination&lt;/a&gt;, Dell’Acqua, Fabrizio; Kogut, Bruce; Perkowski, Patryk (2025), The Review of Economics and Statistics 107 (4)&lt;/li&gt;&lt;li style="box-sizing: border-box; line-height: calc(1.5em + 0.2vw); margin-bottom: 0.75em; padding-left: 0.15em; word-break: break-word;"&gt;&lt;a href="https://www.humorseriously.com/" style="box-sizing: border-box; color: #006fc6; padding: 7px 0px; text-decoration-skip-ink: auto; text-decoration-thickness: auto; text-underline-offset: 1px;"&gt;Humor Is Serious Business: Why Humor Is A Secret Weapon In Business And Life&lt;/a&gt;, Aaker, J; Bagdonas, Naomi (2021)&lt;/li&gt;&lt;/ul&gt;</description><link>http://honeyvig.blogspot.com/2026/06/the-bug-free-workforce-how-ai.html</link><author>noreply@blogger.com (H)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-9165069509664255576.post-3675860527380882283</guid><pubDate>Mon, 11 May 2026 14:41:00 +0000</pubDate><atom:updated>2026-05-11T07:41:18.508-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Accessibility</category><category domain="http://www.blogger.com/atom/ns#">AI</category><category domain="http://www.blogger.com/atom/ns#">frontend</category><category domain="http://www.blogger.com/atom/ns#">Future</category><category domain="http://www.blogger.com/atom/ns#">Performance</category><category domain="http://www.blogger.com/atom/ns#">Privacy</category><category domain="http://www.blogger.com/atom/ns#">Skills</category><category domain="http://www.blogger.com/atom/ns#">webdev</category><title>Stop Ignoring These Frontend Skills—You’ll Need Them Sooner Than You Think</title><description>&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="reader-author-info__container"&gt;&lt;div class="mt4"&gt;&lt;time class="text-body-small-open t-black--light"&gt;
                    &lt;/time&gt;
                  &lt;/div&gt;
                &lt;/div&gt;


                
    &lt;div data-scaffold-immersive-reader-content=""&gt;
      
                  
    &lt;div&gt;
      &lt;div class="reader-article-content reader-article-content--content-blocks" dir="ltr"&gt;
          

      &lt;div class="reader-content-blocks-container"&gt;

            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember60"&gt;
      &lt;strong&gt;Let’s be honest&lt;/strong&gt;: the way we create for the web is evolving at a pace that many people are reluctant to acknowledge.&lt;span class="white-space-pre"&gt; &lt;/span&gt;
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember61"&gt;
      What was once considered “nice to have” just a year ago is quickly
 turning into a “must-have” today. If you’re not keeping an eye on these
 changes, you’ll definitely notice the impact soon.&lt;span class="white-space-pre"&gt; &lt;/span&gt;
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember62"&gt;
      Here are the frontend skills I believe are shifting from “maybe later” to “learn now” over the next 2–3 years:
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember63"&gt;
      &lt;strong&gt;1. AI-Powered Coding Tools&lt;/strong&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;:
 Tools like Copilot and Codeium are more than just a novelty. They’re 
rapidly becoming essential parts of our daily workflow. If you can 
effectively guide, review, and enhance the suggestions that AI provides,
 you’ll be able to deliver your projects faster and with greater 
intelligence.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember64"&gt;
      &lt;strong&gt;2. Real Accessibility &amp;amp; Inclusive Design:&lt;/strong&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;These
 days, accessibility is something we expect rather than just admire. 
Creating experiences that cater to all users right from the beginning 
will really make you stand out. Very soon, it will become essential for 
every project.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember65"&gt;
      &lt;strong&gt;3. Building for Every Device :&lt;/strong&gt;These days, it’s 
not just about web and mobile anymore. Your creations need to look 
fantastic on every screen - whether it’s a smart TV or whatever new tech
 comes our way. Responsive and resilient user interfaces are now the 
standard we should all aim for.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember66"&gt;
      &lt;strong&gt;4. Performance Matters :&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;/strong&gt;Let’s
 face it, nobody wants to deal with sluggish apps. Taking the time to 
profile, optimize, and genuinely care about the user experience is what 
sets the good apart from the truly great.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember67"&gt;
      &lt;strong&gt;5. Privacy-First Frontends;&lt;/strong&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;Trust
 is everything. Make privacy clear, easy to understand, and simple to 
control in your user interface. For many users - and regulators - this 
is already a deal-breaker.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember68"&gt;
      &lt;strong&gt;6. Strong Fundamentals, Flexible Stack:&lt;/strong&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;Frameworks
 may evolve, but the top developers really grasp the essential concepts 
and can easily switch between different tools. Stay curious. Keep 
learning. Don’t limit yourself to just one stack.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember69"&gt;
      &lt;strong&gt;What’s Next?&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;/strong&gt;
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember70"&gt;
      Get ready for more AI in your development tools. The demand for 
user-friendly and privacy-conscious interfaces is only going to rise. 
Expect lightning-fast, resilient apps to become standard on every 
device.&lt;span class="white-space-pre"&gt; &lt;/span&gt;
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember71"&gt;
      By mastering these skills, you won’t just be securing your future 
career; you’ll also unlock opportunities for roles and projects that you
 might not even be aware of yet. If you’re aiming for bigger chances—and
 want the confidence to embrace them—now’s the time to start.&lt;span class="white-space-pre"&gt; &lt;/span&gt;
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember72"&gt;
      Feel free to drop a comment if you’d like an invite, or send me a 
DM if you think there’s a skill that should be added to the list.&lt;span class="white-space-pre"&gt; &lt;/span&gt;
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember73"&gt;
      What are you currently learning to stay ahead? Let’s chat about it in the comments!
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember74"&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description><link>http://honeyvig.blogspot.com/2026/05/stop-ignoring-these-frontend.html</link><author>noreply@blogger.com (H)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-9165069509664255576.post-6829544273073469178</guid><pubDate>Mon, 11 May 2026 12:55:00 +0000</pubDate><atom:updated>2026-05-11T05:55:48.108-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Accessibility</category><category domain="http://www.blogger.com/atom/ns#">UI</category><category domain="http://www.blogger.com/atom/ns#">UX</category><title>Stop Building "Dead" Websites. (The Pixel-Perfect Era is Over)</title><description>&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 class="ember-view reader-text-block__heading-3" id="ember61"&gt;
      Your $50k website is officially a dinosaur. &#129430;
    &lt;/h3&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember62"&gt;
      For a decade, we’ve been obsessed with "Pixel Perfection." We 
argued over hex codes, debated the radius of a button, and spent months 
perfecting "Click Paths."
    &lt;/p&gt;

  






            
        
    &lt;h3 class="ember-view reader-text-block__heading-3" id="ember63"&gt;
      The reality? In 2026, your users don’t want to click through your beautiful menu. They want an answer.
    &lt;/h3&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember64"&gt;
      We are witnessing the violent transition from&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;strong&gt;Deterministic UI&lt;/strong&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;(the static site you built) to&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;strong&gt;Generative UI&lt;/strong&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;(the interface that builds itself around the user).
    &lt;/p&gt;

  










            
  &lt;hr class="reader-divider-block__horizontal-rule" /&gt;



            
        
    &lt;h3 class="ember-view reader-text-block__heading-3" id="ember65"&gt;
      1. The Netflix-ification of Everything
    &lt;/h3&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember66"&gt;
      Remember when you had to browse "Genres" to find a movie? Now, Netflix builds a unique homepage for you the second you log in.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember67"&gt;
      If your SaaS or E-commerce site still looks the same for a 
first-time visitor as it does for a 5-year veteran, you aren't 
"consistent"—you’re irrelevant.&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;strong&gt;Generative UI&lt;/strong&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;means
 the interface morphs based on intent. If the AI detects a user is 
frustrated, the "Help" button shouldn't just be there; it should be the&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;em&gt;only&lt;/em&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;thing there.
    &lt;/p&gt;

  






            
        
    &lt;h3 class="ember-view reader-text-block__heading-3" id="ember68"&gt;
      2. Accessibility is your new SEO
    &lt;/h3&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember69"&gt;
      Here is a hard truth: If an AI Agent (like Gemini or GPT-6) can’t 
"crawl" your site and understand it instantly, you don't exist.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember70"&gt;
            &lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Old way:&lt;/strong&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;Making your site accessible to be "nice."&lt;/li&gt;&lt;li&gt;&lt;strong&gt;New way:&lt;/strong&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;Using
 Semantic HTML because if the AI can’t read your site, it won't 
recommend you to the millions of people using Voice Search and AI 
Personal Assistants.&lt;img class="reader-cover-image__img evi-image lazy-image ember-view" id="ember40" src="https://media.licdn.com/dms/image/v2/D5612AQFeGOrjLw_HVA/article-cover_image-shrink_720_1280/B56Z4NM89FIsAI-/0/1778337961646?e=1779926400&amp;amp;v=beta&amp;amp;t=rfrV7Hr0Oiw_obqQVVy55s_fOWMndl3p5z5IGeyloRI" /&gt;&lt;/li&gt;&lt;/ul&gt;

    &lt;p&gt;&lt;/p&gt;

  






            
        
    &lt;h3 class="ember-view reader-text-block__heading-3" id="ember71"&gt;
      3. The "Invisible" UI (Example: Uber)
    &lt;/h3&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember72"&gt;
      The most successful interface of the last decade is the&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;strong&gt;Uber map&lt;/strong&gt;. Why? Because it’s invisible. You don’t "navigate" a menu to find a car. You see a map, you see a car, you press one button.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember73"&gt;
      The future isn't more buttons; it’s&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;strong&gt;Zero UI&lt;/strong&gt;. It’s systems that use token-driven logic to automate the boring stuff so humans can do the creative stuff.
    &lt;/p&gt;

  










            
  &lt;hr class="reader-divider-block__horizontal-rule" /&gt;



            
        
    &lt;h3 class="ember-view reader-text-block__heading-3" id="ember74"&gt;
      The Bottom Line:
    &lt;/h3&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember75"&gt;
      Stop building for browsers. Start building for&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;strong&gt;behaviors&lt;/strong&gt;.
    &lt;/p&gt;

  







              
    &lt;div class="reader-image-block reader-image-block--full-width"&gt;
      &lt;figure class="reader-image-block__figure"&gt;
          
    &lt;div class="ivm-image-view-model    reader-image-block__img-container"&gt;
        
    &lt;div class="ivm-view-attr__img-wrapper
        
        "&gt;

          &lt;img alt="Article content" class="ivm-view-attr__img--centered  reader-image-block__img evi-image lazy-image ember-view" id="ember76" src="https://media.licdn.com/dms/image/v2/D5612AQEYnpgKKMEXSg/article-inline_image-shrink_1000_1488/B56Z4NKliEKMAQ-/0/1778337341587?e=1779926400&amp;amp;v=beta&amp;amp;t=2gYcObdZh05sNfbJXt_DyHlZD0PA5CcQAVgJv-IH_NQ" /&gt;
    &lt;/div&gt;
  
          &lt;/div&gt;
  

          &lt;figcaption class="reader-image-block__figure-image-caption display-block full-width text-body-small-open t-sans text-align-center t-black--light"&gt;
            
          &lt;/figcaption&gt;
      &lt;/figure&gt;
    &lt;/div&gt;
  





            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember77"&gt;
      
        &lt;br /&gt;
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember78"&gt;
      If your design system requires a manual to understand, you’ve 
already lost. The winners of 2026 will be the ones who blend high-end 
aesthetics with "Invisible" AI logic.
    &lt;/p&gt;

  










            
  &lt;hr class="reader-divider-block__horizontal-rule" /&gt;



            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember79"&gt;
      &lt;strong&gt;I’m calling it: The "Sidebar and Dashboard" layout is officially dead. Who’s brave enough to disagree?&lt;/strong&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;&#128071;
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember80"&gt;
      &lt;em&gt;Drop a comment below: Is your team still stuck in the "Pixel-Perfect" trap, or are you building for the AI era?&lt;/em&gt;
    &lt;/p&gt;</description><link>http://honeyvig.blogspot.com/2026/05/stop-building-dead-websites-pixel.html</link><author>noreply@blogger.com (H)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-9165069509664255576.post-7229268987186895344</guid><pubDate>Fri, 01 May 2026 08:45:00 +0000</pubDate><atom:updated>2026-05-01T01:45:00.117-07:00</atom:updated><title>Identifying Necessary Transparency Moments In Agentic AI (Part 1)</title><description>&lt;p&gt;&amp;nbsp;Designing for agentic AI requires attention to both the system’s 
behavior and the transparency of its actions. Between the black box and 
the data dump lies a more thoughtful approach.&lt;/p&gt;&lt;div class="c-garfield-summary"&gt;&lt;section aria-label="Quick summary" class="article__summary"&gt;explores how to map decision points and reveal the right moments to build trust through clarity, not noise.&lt;/section&gt;&lt;/div&gt;&lt;p&gt;Designing
 for autonomous agents presents a unique frustration. We hand a complex 
task to an AI, it vanishes for 30 seconds (or 30 minutes), and then it 
returns with a result. We stare at the screen. Did it work? Did it 
hallucinate? Did it check the compliance database or skip that step?&lt;/p&gt;&lt;p&gt;We typically respond to this anxiety with one of two extremes. We either keep the system a &lt;strong&gt;Black Box&lt;/strong&gt;, hiding everything to maintain simplicity, or we panic and provide a &lt;strong&gt;Data Dump&lt;/strong&gt;, streaming every log line and API call to the user.&lt;/p&gt;&lt;p&gt;Neither approach directly addresses the nuance needed to provide users with the ideal level of transparency.&lt;/p&gt;&lt;p&gt;The &lt;em&gt;Black Box&lt;/em&gt; leaves users feeling powerless. The &lt;em&gt;Data Dump&lt;/em&gt;
 creates notification blindness, destroying the efficiency the agent 
promised to provide. Users ignore the constant stream of information 
until something breaks, at which point they lack the context to fix it.&lt;/p&gt;&lt;p&gt;We need an organized way to find the balance. In my previous article, “&lt;a href="https://www.smashingmagazine.com/2026/02/designing-agentic-ai-practical-ux-patterns/"&gt;Designing For Agentic AI&lt;/a&gt;”,
 we looked at interface elements that build trust, like showing the AI’s
 intended action beforehand (Intent Previews) and giving users control 
over how much the AI does on its own (Autonomy Dials). But knowing which
 elements to use is only part of the challenge. The harder question for 
designers is knowing when to use them.&lt;/p&gt;&lt;p&gt;How do you know which 
specific moment in a 30-second workflow requires an Intent Preview and 
which can be handled with a simple log entry?&lt;/p&gt;&lt;p&gt;This article provides a method to answer that question. We will walk through the &lt;strong&gt;Decision Node Audit&lt;/strong&gt;.
 This process gets designers and engineers in the same room to map 
backend logic to the user interface. You will learn how to pinpoint the 
exact moments a user needs an update on what the AI is doing. We will 
also cover an &lt;strong&gt;Impact/Risk matrix&lt;/strong&gt; that will help to prioritize which decision nodes to display and any associated design pattern to pair with that decision.&lt;/p&gt;&lt;h2 id="transparency-moments-a-case-study-example"&gt;Transparency Moments: A Case Study Example&amp;nbsp;&lt;/h2&gt;&lt;p&gt;Consider
 Meridian (not real name), an insurance company that uses an agentic AI 
to process initial accident claims. The user uploads photos of vehicle 
damage and the police report. The agent then disappears for a minute 
before returning with a risk assessment and a proposed payout range.&lt;/p&gt;&lt;p&gt;Initially,
 Meridian’s interface simply showed Calculating Claim Status. Users grew
 frustrated. They had submitted several detailed documents and felt 
uncertain about whether the AI had even reviewed the police report, 
which contained mitigating circumstances. The Black Box created 
distrust.&lt;/p&gt;&lt;p&gt;To fix this, the design team conducted a Decision Node 
Audit. They found that the AI performed three distinct, 
probability-based steps, with numerous smaller steps embedded:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Image Analysis&lt;/strong&gt;&lt;br /&gt;The
 agent compared the damage photos against a database of typical car 
crash scenarios to estimate the repair cost. This involved a confidence 
score.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Textual Review&lt;/strong&gt;&lt;br /&gt;It scanned the police 
report for keywords that affect liability (e.g., fault, weather 
conditions, sobriety). This involved a probability assessment of legal 
standing.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Policy Cross Reference&lt;/strong&gt;&lt;br /&gt;It matched 
the claim details against the user’s specific policy terms, searching 
for exceptions or coverage limits. This also involved probabilistic 
matching.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The team turned these steps into transparency moments. The interface sequence was updated to:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Assessing Damage Photos&lt;/strong&gt;: Comparing against 500 vehicle impact profiles.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Reviewing Police Report&lt;/strong&gt;: Analyzing liability keywords and legal precedent.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Verifying Policy Coverage&lt;/strong&gt;: Checking for specific exclusions in your plan.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The
 system still took the same amount of time, but the explicit 
communication about the agent’s internal workings restored user 
confidence. Users understood that the AI was performing the complex task
 it was designed for, and they knew exactly where to focus their 
attention if the final assessment seemed inaccurate. This design choice 
transformed a moment of anxiety into a moment of connection with the 
user.&lt;/p&gt;&lt;h3 id="applying-the-impact-risk-matrix-what-we-chose-to-hide"&gt;Applying the Impact/Risk Matrix: What We Chose to Hide&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/04/identifying-necessary-transparency-moments-agentic-ai-part1/#applying-the-impact-risk-matrix-what-we-chose-to-hide"&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Most
 AI experiences have no shortage of events and decision nodes that could
 potentially be displayed during processing. One of the most critical 
outcomes of the audit was to decide what to keep invisible. In the 
Meridian example, the backend logs generated 50+ events per claim. We 
could have defaulted to displaying each event as they were processed as 
part of the UI. Instead, we applied the risk matrix to prune them:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;em&gt;Log Event:&lt;/em&gt; Pinging Server West-2 for redundancy check.&lt;ul&gt;&lt;li&gt;&lt;em&gt;Filter Verdict:&lt;/em&gt; &lt;strong&gt;Hide.&lt;/strong&gt; (Low Stakes, High Technicality).&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;em&gt;Log Event:&lt;/em&gt; Comparing repair estimate to BlueBook value.&lt;ul&gt;&lt;li&gt;&lt;em&gt;Filter Verdict:&lt;/em&gt; &lt;strong&gt;Show.&lt;/strong&gt; (High Stakes, impacts user’s payout).&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;By
 cutting out the unnecessary details, the important information — like 
the coverage verification — was more impactful. We created an open 
interface and designed an open &lt;em&gt;experience&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;This approach 
uses the idea that people feel better about a service when they can see 
the work being done. By showing the specific steps (Assessing, 
Reviewing, Verifying), we changed a 30-second wait from a time of worry (&lt;em&gt;“Is it broken?”&lt;/em&gt;) to a time of feeling like something valuable is being created (&lt;em&gt;“It’s thinking”&lt;/em&gt;).&lt;/p&gt;&lt;p&gt;Let’s
 now take a closer look at how we can review the decision-making process
 in our products to identify key moments that require clear information.&lt;/p&gt;&lt;div aria-hidden="true" class="c-friskies-box partners partners__lead partners__lead-place partners__external" data-amount="1" data-audience="non-subscriber" data-remove="true" data-rendered="true"&gt;&lt;ul&gt;&lt;a class="partners__native--smashing" href="https://www.smashingmagazine.com/contact/"&gt;
        &lt;picture&gt;
          &lt;source media="(max-width: 600px)"&gt;&lt;/source&gt;
          &lt;img alt="Advertise with Smashing Magazine" width="325" /&gt;
        &lt;/picture&gt;
      &lt;/a&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 id="the-decision-node-audit"&gt;The Decision Node Audit&lt;/h2&gt;&lt;p&gt;Transparency fails when we treat it as a style choice rather than a functional requirement. We have a tendency to ask, &lt;em&gt;“What should the UI look like?”&lt;/em&gt; before we ask, &lt;em&gt;“What is the agent actually deciding?”&lt;/em&gt;&lt;/p&gt;&lt;p&gt;The
 Decision Node Audit is a straightforward way to make AI systems easier 
to understand. It works by carefully mapping out the system’s internal 
process. The main goal is to find and clearly define the exact moments 
where the system stops following its set rules and instead makes a 
choice based on chance or estimation. By mapping this structure, 
creators can show these points of uncertainty directly to the people 
using the system. This changes system updates from being vague 
statements to specific, reliable reports about how the AI reached its 
conclusion.&lt;/p&gt;&lt;p&gt;In addition to the insurance case study above, I 
recently worked with a team building a procurement agent. The system 
reviewed vendor contracts and flagged risks. Originally, the screen 
displayed a simple progress bar: &lt;em&gt;“Reviewing contracts.”&lt;/em&gt; Users hated it. Our research indicated they felt anxious about the legal implications of a missing clause.&lt;/p&gt;&lt;p&gt;We
 fixed this by conducting a Decision Node Audit. I’ve included a 
step-by-step checklist for conducting this audit at the conclusion of 
this article.&lt;/p&gt;&lt;p&gt;We ran a session with the engineers and outlined how
 the system works. We identified “Decision Points” — moments where the 
AI had to choose between two good options.&lt;/p&gt;&lt;p&gt;In standard computer 
programs, the process is clear: if A happens, then B will always happen.
 In AI systems, the process is often based on chance. The AI thinks A is
 probably the best choice, but it might only be 65% certain.&lt;/p&gt;&lt;p&gt;In 
the contract system, we found a moment when the AI checked the liability
 terms against our company rules. It was rarely a perfect match. The AI 
had to decide if a 90% match was good enough. This was a key decision 
point.&lt;/p&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://files.smashing.media/articles/identifying-necessary-transparency-moments-agentic-ai-part1/1-decision-node-structure.png"&gt;&lt;img alt="The diagram shows how to connect a hidden system decision based on probability (an Ambiguity Point) to a visible moment of explanation for the user (a Transparency Moment)." height="437" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/identifying-necessary-transparency-moments-agentic-ai-part1/1-decision-node-structure.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;&lt;strong&gt;Figure 1:&lt;/strong&gt;
 This diagram shows how to connect a hidden system decision based on 
probability (an Ambiguity Point) to a visible moment of explanation for 
the user (a Transparency Moment).&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;Once we identified this node, we exposed it to the user. Instead of &lt;em&gt;“Reviewing contracts,”&lt;/em&gt; the interface updated to say: &lt;em&gt;“Liability clause varies from standard template. Analyzing risk level.”&lt;/em&gt;&lt;/p&gt;&lt;p&gt;This
 specific update gave users confidence. They knew the agent checked the 
liability clause. They understood the reason for the delay and gained 
trust that the desired action was occurring on the back end. They also 
knew where to dig in deeper once the agent generated the contract.&lt;/p&gt;&lt;p&gt;To
 check how the AI makes decisions, you need to work closely with your 
engineers, product managers, business analysts, and key people who are 
making the choices (often hidden) that affect how the AI tool functions.
 Draw out the steps the tool takes. Mark every spot where the process 
changes direction because a probability is met. These are the places 
where you should focus on being more transparent.&lt;/p&gt;&lt;p&gt;As shown in Figure 2 below, the Decision Node Audit involves these steps:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Get the team together:&lt;/strong&gt;
 Bring in the product owners, business analysts, designers, key 
decision-makers, and the engineers who built the AI. For example,&lt;/p&gt;&lt;p&gt;Think
 about a product team building an AI tool designed to review messy legal
 contracts. The team includes the UX designer, the product manager, the 
UX researcher, a practicing lawyer who acts as the subject-matter 
expert, and the backend engineer who wrote the text-analysis code.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Draw the whole process:&lt;/strong&gt; Document every step the AI takes, from the user’s first action to the final result.&lt;/p&gt;&lt;p&gt;The
 team stands at a whiteboard and sketches the entire sequence for a key 
workflow that involves the AI searching for a liability clause in a 
complex contract. The lawyer uploads a fifty-page PDF&amp;nbsp;→ The system 
converts the document into readable text.&amp;nbsp;→ The AI scans the pages for 
liability clauses.&amp;nbsp;→ The user waits.&amp;nbsp;→ Moments or minutes later, the 
tool highlights the found paragraphs in yellow on the user interface. 
They do this for many other workflows that the tool accommodates as 
well.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Find where things are unclear:&lt;/strong&gt; Look at the process map for any spot where the AI compares options or inputs that don’t have one perfect match.&lt;/p&gt;&lt;p&gt;The
 team looks at the whiteboard to spot the ambiguous steps. Converting an
 image to text follows strict rules. Finding a specific liability clause
 involves guesswork. Every firm writes these clauses differently, so the
 AI has to weigh multiple options and make a prediction instead of 
finding an exact word match.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Identify the ‘best guess’ steps:&lt;/strong&gt;
 For each unclear spot, check if the system uses a confidence score (for
 example, is it 85% sure?). These are the points where the AI makes a 
final choice.&lt;/p&gt;&lt;p&gt;The system has to guess (give a probability) which 
paragraph(s) closely resemble a standard liability clause. It assigns a 
confidence score to its best guess. That guess is a decision node. The 
interface needs to tell the lawyer it is highlighting a potential match,
 rather than stating it found the definitive clause.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Examine the choice:&lt;/strong&gt;
 For each choice point, figure out the specific internal math or 
comparison being done (e.g., matching a part of a contract to a policy 
or comparing a picture of a broken car to a library of damaged car 
photos).&lt;/p&gt;&lt;p&gt;The engineer explains that the system compares the 
various paragraphs against a database of standard liability clauses from
 past firm cases. It calculates a text similarity score to decide on a 
match based on probabilities.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Write clear explanations:&lt;/strong&gt; Create messages for the user that clearly describe the specific internal action happening when the AI makes a choice.&lt;/p&gt;&lt;p&gt;The content designer writes a specific message for this exact moment. The text reads: &lt;em&gt;Comparing document text to standard firm clauses to identify potential liability risks.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Update the screen:&lt;/strong&gt; Put these new, clear explanations into the user interface, replacing vague messages like &lt;em&gt;“Reviewing contracts.”&lt;/em&gt;&lt;/p&gt;&lt;p&gt;The
 design team removes the generic Processing PDF loading spinner. They 
insert the new explanation into a status bar located right above the 
document viewer while the AI thinks.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Check for Trust:&lt;/strong&gt;
 Make sure the new screen messages give users a simple reason for any 
wait time or result, which should make them feel more confident and 
trusting.&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://files.smashing.media/articles/identifying-necessary-transparency-moments-agentic-ai-part1/2-decision-nodes-ai-legal-tool.png"&gt;&lt;img alt="Comic where a product team maps the decision nodes of an AI legal tool to design transparent interface messages." height="437" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/identifying-necessary-transparency-moments-agentic-ai-part1/2-decision-nodes-ai-legal-tool.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;&lt;strong&gt;Figure 2:&lt;/strong&gt;
 A product team maps the decision nodes of an AI legal tool to design 
transparent interface messages. (Comic generated using Google 
Gemini/Nano Banana)&lt;/figcaption&gt;&lt;/figure&gt;&lt;h3 id="the-impact-risk-matrix"&gt;The Impact/Risk Matrix&lt;/h3&gt;&lt;p&gt;Once
 you look closely at the AI’s process, you’ll likely find many points 
where it makes a choice. An AI might make dozens of small choices for a 
single complex task. Showing them all creates too much unnecessary 
information. You need to group these choices.&lt;/p&gt;&lt;p&gt;You can use an &lt;strong&gt;Impact/Risk Matrix&lt;/strong&gt; to sort these choices based on the types of action(s) the AI is taking. Here are examples of impact/risk matrices:&lt;/p&gt;&lt;p&gt;First, look for low-stakes and low-impact decisions.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Low Stakes / Low Impact&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;em&gt;Example:&lt;/em&gt; Organizing a file structure or renaming a document.&lt;/li&gt;&lt;li&gt;&lt;em&gt;Transparency Need:&lt;/em&gt; Minimal. A subtle toast notification or a log entry suffices. Users can undo these actions easily.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Then identify the high-stakes and high-impact decisions.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;High Stakes / High Impact&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;em&gt;Example:&lt;/em&gt; Rejecting a loan application or executing a stock trade.&lt;/li&gt;&lt;li&gt;&lt;em&gt;Transparency Need:&lt;/em&gt; High. These actions require Proof of Work. The system must demonstrate the rationale before or immediately as it acts.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Consider
 a financial trading bot that treats all buy/sell orders the same. It 
executes a $5 trade with the same opacity as a $50,000 trade. Users 
might question whether the tool recognizes the potential impact of 
transparency on trading on a large dollar amount. They need the system 
to pause and show its work for the high-stakes trades. The solution is 
to introduce a Reviewing Logic state for any transaction exceeding a 
specific dollar amount, allowing the user to see the factors driving the
 decision before execution.&lt;/p&gt;&lt;h3 id="mapping-nodes-to-patterns-a-design-pattern-selection-rubric"&gt;Mapping Nodes to Patterns: A Design Pattern Selection Rubric&lt;/h3&gt;&lt;p&gt;Once
 you have identified your experience’s key decision nodes, you must 
decide which UI pattern applies to each one you’ll display. In Designing
 For Agentic AI, we introduced patterns like the Intent Preview (for 
high-stakes control) and the Action Audit (for retrospective safety). 
The decisive factor in choosing between them is reversibility.&lt;/p&gt;&lt;p&gt;We filter every decision node through the impact matrix in order to assign the correct pattern:&lt;/p&gt;&lt;p&gt;&lt;strong&gt;High Stakes &amp;amp; Irreversible:&lt;/strong&gt;
 These nodes require an Intent Preview. Because the user cannot easily 
undo the action (e.g., permanently deleting a database), the 
transparency moment must happen before execution. The system must pause,
 explain its intent, and require confirmation.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;High Stakes &amp;amp; Reversible:&lt;/strong&gt;
 These nodes can rely on the Action Audit &amp;amp; Undo pattern. If the 
AI-powered sales agent moves a lead to a different pipeline, it can do 
so autonomously as long as it notifies the user and offers an immediate 
Undo button.&lt;/p&gt;&lt;p&gt;By strictly categorizing nodes this way, we avoid 
“alert fatigue.” We reserve the high-friction Intent Preview only for 
the truly irreversible moments, while relying on the Action Audit to 
maintain speed for everything else.&lt;/p&gt;&lt;table class="tablesaw break-out"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;br /&gt;&lt;/th&gt;&lt;th&gt;Reversible&lt;/th&gt;&lt;th&gt;Irreversible&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td data-label=""&gt;&lt;strong&gt;Low Impact&lt;/strong&gt;&lt;/td&gt;&lt;td data-label="Reversible"&gt;&lt;strong&gt;Type&lt;/strong&gt;: Auto-Execute&lt;br /&gt;&lt;strong&gt;UI&lt;/strong&gt;: Passive Toast / Log&lt;br /&gt;&lt;em&gt;Ex: Renaming a file&lt;/em&gt;&lt;/td&gt;&lt;td data-label="Irreversible"&gt;&lt;strong&gt;Type&lt;/strong&gt;: Confirm&lt;br /&gt;&lt;strong&gt;UI&lt;/strong&gt;: Simple Undo option&lt;br /&gt;&lt;em&gt;Ex: Archiving an email&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td data-label=""&gt;&lt;strong&gt;High Impact&lt;/strong&gt;&lt;/td&gt;&lt;td data-label="Reversible"&gt;&lt;strong&gt;Type&lt;/strong&gt;: Review&lt;br /&gt;&lt;strong&gt;UI&lt;/strong&gt;: Notification + Review Trail&lt;br /&gt;&lt;em&gt;Ex: Sending a draft to a client&lt;/em&gt;&lt;/td&gt;&lt;td data-label="Irreversible"&gt;&lt;strong&gt;Type&lt;/strong&gt;: Intent preview&lt;br /&gt;&lt;strong&gt;UI&lt;/strong&gt;: Modal / Explicit Permission&lt;br /&gt;&lt;em&gt;Ex: Deleting a server&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Table 1:&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;The impact and reversibility matrix can then be used to map your moments of transparency to design patterns.&lt;/em&gt;&lt;/p&gt;&lt;h3 id="qualitative-validation-the-wait-why-test"&gt;Qualitative Validation: “The Wait, Why?” Test&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/04/identifying-necessary-transparency-moments-agentic-ai-part1/#qualitative-validation-the-wait-why-test"&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;You
 can identify potential nodes on a whiteboard, but you must validate 
them with human behavior. You need to verify whether your map matches 
the user’s mental model. I use a protocol called the &lt;strong&gt;“Wait, Why?” Test&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;Ask a user to watch the agent complete a task. Instruct them to speak aloud. Whenever they ask a question, &lt;em&gt;“Wait, why did it do that?”&lt;/em&gt; or &lt;em&gt;“Is it stuck?”&lt;/em&gt; or &lt;em&gt;“Did it hear me?”&lt;/em&gt; — you mark a timestamp.&lt;/p&gt;&lt;p&gt;These
 questions signal user confusion. The user feels their control slipping 
away. For example, in a study for a healthcare scheduling assistant, 
users watched the agent book an appointment. The screen sat static for 
four seconds. Participants consistently asked, &lt;em&gt;“Is it checking my calendar or the doctor’s?”&lt;/em&gt;&lt;/p&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://files.smashing.media/articles/identifying-necessary-transparency-moments-agentic-ai-part1/3-wait-why-protocol.png"&gt;&lt;img alt="The Wait, Why? Protocol. A timeline illustrating how silence creates anxiety. By mapping the specific moment users ask ‘Is it stuck?’, designers can insert transparency exactly when it is needed." height="437" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/identifying-necessary-transparency-moments-agentic-ai-part1/3-wait-why-protocol.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;&lt;strong&gt;Figure 3:&lt;/strong&gt;
 The Wait, Why? Protocol. A timeline illustrating how silence creates 
anxiety. By mapping the specific moment users ask ‘Is it stuck?’, 
designers can insert transparency exactly when it is needed.&amp;nbsp;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;That question revealed a missing &lt;strong&gt;Transparency Moment&lt;/strong&gt;. The system needed to split that four-second wait into two distinct steps: &lt;em&gt;“Checking your availability”&lt;/em&gt; followed by &lt;em&gt;“Syncing with provider schedule.”&lt;/em&gt;&lt;/p&gt;&lt;p&gt;This small change reduced users’ expressed levels of anxiety.&lt;/p&gt;&lt;p&gt;Transparency
 fails when it only describes a system action. The interface must 
connect the technical process to the user’s specific goal. A screen 
displaying &lt;em&gt;“Checking your availability”&lt;/em&gt; falls flat because it lacks context. The user understands that the AI is looking at a calendar, but they do not know why.&lt;/p&gt;&lt;p&gt;We
 must pair the action with the outcome. The system needs to split that 
four-second wait into two distinct steps. First, the interface displays &lt;em&gt;“Checking your calendar to find open times.”&lt;/em&gt; Then it updates to &lt;em&gt;“Syncing with the provider’s schedule to secure your appointment.”&lt;/em&gt; This grounds the technical process in the user’s actual life.&lt;/p&gt;&lt;p&gt;Consider
 an AI managing inventory for a local cafe. The system encounters a 
supply shortage. An interface reading “contacting vendor” or “reviewing 
options” creates anxiety. The manager wonders if the system is canceling
 the order or buying an expensive alternative. A better approach is to 
explain the intended result: &lt;em&gt;“Evaluating alternative suppliers to maintain your Friday delivery schedule.”&lt;/em&gt; This tells the user exactly what the AI is trying to achieve.&lt;/p&gt;&lt;div aria-hidden="true" class="c-friskies-box partners partners__lead partners__lead-place partners__external" data-amount="1" data-audience="non-subscriber" data-remove="true"&gt;&lt;/div&gt;&lt;h2 id="operationalizing-the-audit"&gt;Operationalizing the Audit&amp;nbsp;&lt;/h2&gt;&lt;p&gt;You
 have completed the Decision Node Audit and filtered your list through 
the Impact and Risk Matrix. You now have a list of essential moments for
 being transparent. Next, you need to create them in the UI. This step 
requires teamwork across different departments. You can’t design 
transparency by yourself using a design tool. You need to understand how
 the system works behind the scenes.&lt;/p&gt;&lt;p&gt;Start with a &lt;strong&gt;Logic Review&lt;/strong&gt;.
 Meet with your lead system designer. Bring your map of decision nodes. 
You need to confirm that the system can actually share these states. I 
often find that the technical system doesn’t reveal the exact state I 
want to show. The engineer might say the system just returns a general 
“working” status. You must push for a detailed update. You need the 
system to send a specific notice when it switches from reading text to 
checking rules. Without that technical connection, your design is 
impossible to build.&lt;/p&gt;&lt;p&gt;Next, involve the Content Design team. You 
have the technical reason for the AI’s action, but you need a clear, 
human-friendly explanation. Engineers provide the underlying process, 
but content designers provide the way it’s communicated. Do not write 
these messages alone. A developer might write &lt;em&gt;“Executing function 402,”&lt;/em&gt; which is technically correct but meaningless to the user. A designer might write &lt;em&gt;“Thinking,”&lt;/em&gt; which is friendly but too vague. A content strategist finds the right middle ground. They create specific phrases, such as &lt;em&gt;“Scanning for liability risks”&lt;/em&gt;, that show the AI is working without confusing the user.&lt;/p&gt;&lt;p&gt;Finally,
 test the transparency of your messages. Don’t wait until the final 
product is built to see if the text works. I conduct comparison tests on
 simple prototypes where the only thing that changes is the status 
message. For example, I show one group (Group A) a message that says &lt;em&gt;“Verifying identity”&lt;/em&gt; and another group (Group B) a message that says &lt;em&gt;“Checking government databases”&lt;/em&gt;
 (these are made-up examples, but you understand the point). Then I ask 
them which AI feels safer. You’ll often discover that certain words 
cause worry, while others build trust. You must treat the wording as 
something you need to test and prove effective.&lt;/p&gt;&lt;h3 id="how-this-changes-the-design-process"&gt;How This Changes the Design Process&lt;/h3&gt;&lt;p&gt;Conducting
 these audits has the potential to strengthen how a team works together.
 We stop handing off polished design files. We start using messy 
prototypes and shared spreadsheets. The core tool becomes a &lt;strong&gt;transparency matrix&lt;/strong&gt;.
 Engineers and the content designers edit this spreadsheet together. 
They map the exact technical codes to the words the user will read.&lt;/p&gt;&lt;p&gt;Teams
 will experience friction during the logic review. Imagine a designer 
asking the engineer how the AI decides to decline a transaction 
submitted on an expense report. The engineer might say the backend only 
outputs a generic status code like &lt;em&gt;“Error: Missing Data”.&lt;/em&gt; The 
designer states that this isn’t actionable information on the screen. 
The designer negotiates with the engineer to create a specific technical
 hook. The engineer writes a new rule so the system reports exactly what
 is missing, such as a missing receipt image.&lt;/p&gt;&lt;p&gt;Content designers act as translators during this phase. A developer might write a technically accurate string like &lt;em&gt;“Calculating confidence threshold for vendor matching.”&lt;/em&gt;
 A content designer translates that string into a phrase that builds 
trust for a specific outcome. The strategist rewrites it as &lt;em&gt;“Comparing local vendor prices to secure your Friday delivery.”&lt;/em&gt; The user understands the action and the result.&lt;/p&gt;&lt;p&gt;The
 entire cross-functional team sits in on user testing sessions. They 
watch a real person react to different status messages. Seeing a user 
panic because the screen says &lt;em&gt;“Executing trade”&lt;/em&gt; forces the team to rethink their approach. The engineers and designers align on better wording. They change the text to &lt;em&gt;“Verifying sufficient funds”&lt;/em&gt; before buying stock. Testing together guarantees the final interface serves both the system logic and the user’s peace of mind.&lt;/p&gt;&lt;p&gt;It
 does require time to incorporate these additional activities into the 
team’s calendar. However, the end result should be a team that 
communicates more openly, and users who have a better understanding of 
what their AI-powered tools are doing on their behalf (and why). This &lt;strong&gt;integrated approach&lt;/strong&gt; is a cornerstone of designing truly trustworthy AI experiences.&lt;/p&gt;&lt;h2 id="trust-is-a-design-choice"&gt;Trust Is A Design Choice&lt;/h2&gt;&lt;p&gt;We
 often view trust as an emotional byproduct of a good user experience. 
It is easier to view trust as a mechanical result of predictable 
communication.&lt;/p&gt;&lt;p&gt;We build trust by showing the right information at 
the right time. We destroy it by overwhelming the user or hiding the 
machinery completely.&lt;/p&gt;&lt;p&gt;Start with the Decision Node Audit, 
particularly for agentic AI tools and products. Find the moments where 
the system makes a judgment call. Map those moments to the Risk Matrix. 
If the stakes are high, open the box. Show the work.&lt;/p&gt;&lt;p&gt;In the next 
article, we will look at how to design these moments: how to write the 
copy, structure the UI, and handle the inevitable errors when the agent 
gets it wrong.&lt;/p&gt;&lt;h2 id="appendix-the-decision-node-audit-checklist"&gt;Appendix: The Decision Node Audit Checklist&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Phase 1: Setup and Mapping&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;✅ Get the team together:&lt;/strong&gt; Bring in the product owners, business analysts, designers, key decision-makers, and the engineers who built the AI.&lt;/p&gt;&lt;p&gt;&lt;em&gt;Hint:&lt;/em&gt; You need the engineers to explain the actual backend logic. Do not attempt this step alone.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;✅ Draw the whole process:&lt;/strong&gt; Document every step the AI takes, from the user’s first action to the final result.&lt;/p&gt;&lt;p&gt;&lt;em&gt;Hint:&lt;/em&gt; A physical whiteboard session often works best for drawing out these initial steps.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Phase 2: Locating the Hidden Logic&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;✅ Find where things are unclear:&lt;/strong&gt; Look at the process map for any spot where the AI compares options or inputs that do not have one perfect match.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;✅ Identify the best guess steps:&lt;/strong&gt;
 For each unclear spot, check if the system uses a confidence score. For
 example, ask if the system is 85 percent sure. These are the points 
where the AI makes a final choice.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;✅ Examine the choice:&lt;/strong&gt;
 For each choice point, figure out the specific internal math or 
comparison being done. An example is matching a part of a contract to a 
policy. Another example involves comparing a picture of a broken car to a
 library of damaged car photos.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Phase 3: Creating the User Experience&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;✅ Write clear explanations:&lt;/strong&gt; Create messages for the user that clearly describe the specific internal action happening when the AI makes a choice.&lt;/p&gt;&lt;p&gt;&lt;em&gt;Hint:&lt;/em&gt;
 Ground your messages in concrete reality. If an AI books a meeting with
 a client at a local cafe, tell the user the system is checking the cafe
 reservation system.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;✅ Update the screen:&lt;/strong&gt; Put 
these new, clear explanations into the user interface. Replace vague 
messages like Reviewing contracts with your specific explanations.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;✅ Check for Trust:&lt;/strong&gt;
 Make sure the new screen messages give users a simple reason for any 
wait time or result. This should make them feel confident and trusting.&lt;/p&gt;&lt;p&gt;&lt;em&gt;Hint:&lt;/em&gt; Test these messages with actual users to verify they understand the specific outcome being achieved.&lt;/p&gt;</description><link>http://honeyvig.blogspot.com/2026/05/identifying-necessary-transparency.html</link><author>noreply@blogger.com (H)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-9165069509664255576.post-4424176700041561457</guid><pubDate>Thu, 30 Apr 2026 06:56:00 +0000</pubDate><atom:updated>2026-04-29T23:56:00.117-07:00</atom:updated><title>The UX Designer’s Nightmare: When “Production-Ready” Becomes A Design Deliverable</title><description>&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="c-garfield-summary"&gt;&lt;section aria-label="Quick summary" class="article__summary"&gt;In
 a rush to embrace AI, the industry is redefining what it means to be a 
UX designer, blurring the line between design and engineering. Carrie 
Webster explores what’s gained, what’s lost, and why designers need to 
remain the guardians of the user experience.&lt;/section&gt;&lt;/div&gt;&lt;p&gt;In early 2026, I noticed that the UX designer’s toolkit seemed to shift overnight. The industry standard &lt;em&gt;“Should designers code?”&lt;/em&gt;
 debate was abruptly settled by the market, not through a consensus of 
our craft, but through the brute force of job requirements. If you 
browse LinkedIn today, you’ll notice a stark change: UX roles 
increasingly demand &lt;strong&gt;&lt;a href="https://www.refontelearning.com/blog/ui-ux-designer-engineering-in-2026-crafting-future-ready-user-experiences"&gt;AI-augmented development&lt;/a&gt;&lt;/strong&gt;, &lt;strong&gt;technical orchestration,&lt;/strong&gt; and &lt;strong&gt;production-ready prototyping.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;For
 many, including myself, this is the ultimate design job nightmare. We 
are being asked to deliver both the “vibe” and the “code” 
simultaneously, using AI agents to bridge a technical gap that 
previously took years of computer science knowledge and coding 
experience to cross. But as the industry rushes to meet these new 
expectations, they are discovering that AI-generated functional code is 
not always &lt;em&gt;good&lt;/em&gt; code.&lt;/p&gt;&lt;h2 id="the-linkedin-pressure-cooker-role-creep-in-2026"&gt;The LinkedIn Pressure Cooker: Role Creep In 2026&lt;/h2&gt;&lt;p&gt;The job market is sending a clear signal. While traditional graphic design roles are expected to grow by only &lt;strong&gt;3%&lt;/strong&gt; through 2034, UX, UI, and &lt;a href="https://www.nobledesktop.com/careers/designer/job-outlook#:~:text=The%20projected%20future%20growth%20figures%20for%20Digital,job%20growth%20(which%20lies%20somewhere%20around%205%25)."&gt;Product Design roles&lt;/a&gt; are projected to grow by &lt;strong&gt;16%&lt;/strong&gt; over the same period.&lt;/p&gt;&lt;p&gt;However, this growth is increasingly tied to the rise of &lt;strong&gt;AI product development&lt;/strong&gt;,
 where “design skills” have recently become the #1 most in-demand 
capability, even ahead of coding and cloud infrastructure. Companies 
building these platforms are no longer just looking for visual 
designers; they need professionals who can “&lt;a href="https://humbldesign.io/blog-posts/will-ai-replace-designers-2026"&gt;translate technical capability into human-centered experiences&lt;/a&gt;.”&lt;/p&gt;&lt;p&gt;This
 creates a high-stakes environment for the UX designer. We are no longer
 just responsible for the interface; we are expected to understand the 
technical logic well enough to ensure that complex AI capabilities feel 
intuitive, safe, and useful for the human on the other side of the 
screen. Designers are being pushed toward a &lt;strong&gt;“design engineer” model&lt;/strong&gt;, where we must bridge the gap between abstract &lt;a href="https://www.refontelearning.com/blog/ui-ux-designer-engineering-in-2026-crafting-future-ready-user-experiences#skills-and-competencies-for-the-2026-uiux-designer-3"&gt;AI logic and user-facing code&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;A &lt;a href="https://www.lyssna.com/blog/ux-design-trends/"&gt;recent survey&lt;/a&gt; found that &lt;strong&gt;73% of designers&lt;/strong&gt;
 now view AI as a primary collaborator rather than just a tool. However,
 this “collaboration” often looks like “role creep.” Recruiters are 
often not just looking for someone who understands user empathy and 
information architecture — they want someone who can also prompt a React
 component into existence and push it to a repository!&lt;/p&gt;&lt;p&gt;This shift has created a &lt;strong&gt;competency gap&lt;/strong&gt;.&lt;/p&gt;&lt;blockquote&gt;As
 an experienced senior designer who has spent decades mastering the 
nuances of cognitive load, accessibility standards, and ethnographic 
research, I am suddenly finding myself being judged on my ability to 
debug a CSS Flexbox issue or manage a Git branch.&lt;/blockquote&gt;&lt;p&gt;The nightmare isn’t the technology itself. It’s the &lt;strong&gt;reallocation of value&lt;/strong&gt;.&lt;/p&gt;&lt;blockquote class="pull-quote"&gt;&lt;p&gt;&lt;a aria-label="Share on Twitter" class="pull-quote__link" href="https://twitter.com/share?text=%0aBusinesses%20are%20beginning%20to%20value%20the%20speed%20of%20output%20over%20the%20quality%20of%20the%20experience,%20fundamentally%20changing%20what%20it%20means%20to%20be%20a%20%e2%80%9csuccessful%e2%80%9d%20designer%20in%202026.%0a&amp;amp;url=https://smashingmagazine.com%2f2026%2f04%2fproduction-ready-becomes-design-deliverable-ux%2f"&gt;Businesses
 are beginning to value the speed of output over the quality of the 
experience, fundamentally changing what it means to be a “successful” 
designer in 2026.&lt;/a&gt;&lt;/p&gt;&lt;div class="pull-quote__quotation"&gt;&lt;div class="pull-quote__bg"&gt;&lt;span class="pull-quote__symbol"&gt;“&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://files.smashing.media/articles/ux-designer-nightmare-production-ready-becomes-design-deliverable/1-figma.jpg"&gt;&lt;img alt="Figma to AI code ad" height="450" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ux-designer-nightmare-production-ready-becomes-design-deliverable/1-figma.jpg" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;Tools that allow designers to switch from design to code. (Image source: &lt;a href="https://www.figma.com/community/plugin/1443774571835235184/figma-to-ai-code-by-designcode"&gt;Figma&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;h3 id="the-competence-trap-two-job-skill-sets-one-average-result"&gt;The Competence Trap: Two Job Skill Sets, One Average Result&lt;/h3&gt;&lt;p&gt;There
 is potentially a very dangerous myth circulating in boardrooms that AI 
makes a designer “equal” to an engineer. This narrative suggests that 
because an LLM can generate a functional JavaScript event handler, the 
person prompting it doesn’t need to understand the underlying logic. In 
reality, attempting to master two disparate, deep fields simultaneously 
will most likely lead to being &lt;strong&gt;averagely competent&lt;/strong&gt; at both.&lt;/p&gt;&lt;h3 id="the-averagely-competent-dilemma"&gt;The “Averagely Competent” Dilemma&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/04/production-ready-becomes-design-deliverable-ux/#the-averagely-competent-dilemma"&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;For
 a senior UX designer to become a senior-level coder is like asking a 
master chef to also be a master plumber because “they both work in the 
kitchen.” You might get the water running, but you won’t know why the 
pipes are rattling.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;The “cognitive offloading” risk.&lt;/strong&gt;&lt;br /&gt;Research
 shows that while AI can speed up task completion, it often leads to a 
significant decrease in conceptual mastery. In a controlled study, 
participants using AI assistance scored &lt;a href="https://www.psychologytoday.com/au/blog/the-asymmetric-brain/202602/cognitive-offloading-using-ai-reduces-new-skill-formation"&gt;17% lower&lt;/a&gt; on comprehension tests than those who coded by hand.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The debugging gap.&lt;/strong&gt;&lt;br /&gt;The largest performance gap between AI-reliant users and hand-coders is in &lt;a href="https://www.anthropic.com/research/AI-assistance-coding-skills"&gt;debugging&lt;/a&gt;. When a designer uses AI to write code they don’t fully understand, they don’t have the ability to identify &lt;em&gt;when&lt;/em&gt; and &lt;em&gt;why&lt;/em&gt; it fails.&lt;/li&gt;&lt;/ul&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://files.smashing.media/articles/ux-designer-nightmare-production-ready-becomes-design-deliverable/2-ai-assistance-coding-skills-speed.png"&gt;&lt;img alt="A chart showing how AI assistance impacts coding speed and skill formation " height="451" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ux-designer-nightmare-production-ready-becomes-design-deliverable/2-ai-assistance-coding-skills-speed.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;Using AI tools impedes coding skill formation. (Image source: &lt;a href="https://www.anthropic.com/research/AI-assistance-coding-skills"&gt;Anthropic&lt;/a&gt;)&amp;nbsp;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;So,
 if a designer ships an AI-generated component that breaks during a 
high-traffic event and cannot manually trace the logic, they are no 
longer an expert. They are now a liability.&lt;/p&gt;&lt;h3 id="the-high-cost-of-unoptimised-code"&gt;The High Cost Of Unoptimised Code&amp;nbsp;&lt;/h3&gt;&lt;p&gt;Any
 experienced code engineer will tell you that creating code with AI 
without the right prompt leads to a lot of rework. Because most 
designers lack the technical foundation to audit the code the AI gives 
them, they are inadvertently shipping massive amounts of &lt;a href="https://gocrossbridge.com/blog/ai-generated-code/"&gt;“Quality Debt”&lt;/a&gt;.&lt;/p&gt;&lt;h2 id="common-issues-in-designer-generated-ai-code"&gt;Common Issues In Designer-Generated AI Code&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;The security flaw&lt;/strong&gt;&lt;br /&gt;Recent reports indicate that up to &lt;a href="https://www.sherlockforensics.com/pages/ai-code-security-report-2026.html"&gt;92% of AI-generated codebases&lt;/a&gt;
 contain at least one critical vulnerability. A designer might see a 
functioning login form, unaware that it has an 86% failure rate in XSS 
defense, which are the security measures aimed at preventing attackers 
from injecting malicious scripts into trusted websites.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The accessibility illusion&lt;/strong&gt;&lt;br /&gt;AI
 often generates “functional” applications that lack semantic integrity.
 A designer might prompt a “beautiful and functional toggle switch,” but
 the AI may provide a non-semantic &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; that lacks keyboard focus and screen-reader compatibility, creating &lt;a href="https://www.levelaccess.com/blog/accessibility-debt-in-software-development-and-how-to-engineer-it-out/"&gt;Accessibility Debt&lt;/a&gt; that is expensive to fix later.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The performance penalty&lt;/strong&gt;&lt;br /&gt;AI-generated code tends to be verbose. AI is linked to &lt;a href="https://www.netcorpsoftwaredevelopment.com/blog/ai-generated-code-statistics"&gt;4x more code duplication&lt;/a&gt;
 than human-written code. This verbosity slows down page loads, creates 
massive CSS files, and negatively impacts SEO. To a business, the task 
looks “done.” To a user with a slow connection or a screen reader, the 
site is a nightmare.&lt;/li&gt;&lt;/ul&gt;&lt;h2 id="creating-more-work-not-less"&gt;Creating More Work, Not Less&lt;/h2&gt;&lt;p&gt;The promise of AI was that designers could ship features without bothering the engineers. The reality has been the birth of a &lt;strong&gt;“Rework Tax”&lt;/strong&gt; that is draining engineering resources across the industry.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Cleaning up&lt;/strong&gt;&lt;br /&gt;Organisations are finding that while velocity increases, incidents per Pull Request are also rising by &lt;a href="https://blog.exceeds.ai/ai-code-analysis-benchmark-reports/"&gt;23.5%&lt;/a&gt;.
 Some engineering teams now spend a significant portion of their week 
cleaning up “AI slop” delivered by design teams who skipped a rigorous 
review process.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The communication gap&lt;/strong&gt;&lt;br /&gt;Only &lt;a href="https://www.lyssna.com/blog/ux-design-trends/"&gt;69% of designers&lt;/a&gt; feel AI improves the quality of their work, compared to &lt;strong&gt;82% of developers&lt;/strong&gt;. This gap exists because “code that compiles” is not the same as “code that is maintainable.”&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;When
 a designer hands off AI-generated code that ignores a company’s 
internal naming conventions or management patterns, they aren’t helping 
the engineer; they are creating a puzzle that someone else has to solve 
later.&lt;/p&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://files.smashing.media/articles/ux-designer-nightmare-production-ready-becomes-design-deliverable/3-issues-developers-face-ai-generated-code.jpg"&gt;&lt;img alt="Typical issues that developers face with AI-generated code" height="600" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ux-designer-nightmare-production-ready-becomes-design-deliverable/3-issues-developers-face-ai-generated-code.jpg" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;Typical issues that developers face with AI-generated code. (Image source: &lt;a href="https://www.netcorpsoftwaredevelopment.com/blog/ai-generated-code-statistics"&gt;Netcorp&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;h3 id="the-solution"&gt;The Solution&amp;nbsp;&lt;/h3&gt;&lt;p&gt;We need to move away from the nightmare of the “&lt;strong&gt;Solo Full-Stack Designer&lt;/strong&gt;” and toward a model of &lt;strong&gt;designer/coder collaboration&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;The ideal reality:&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;The Partnership&lt;/strong&gt;&lt;br /&gt;Instead of designers trying to be mediocre coders, they should work in a &lt;strong&gt;human-AI-human loop&lt;/strong&gt;. A senior UX designer should work &lt;em&gt;with&lt;/em&gt; an engineer to use AI; the designer creates prompts for &lt;strong&gt;intent, accessibility, and user flow&lt;/strong&gt;, while the engineer creates prompts for &lt;strong&gt;architecture and performance&lt;/strong&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Design systems as guardrails&lt;/strong&gt;&lt;br /&gt;To prevent accessibility debt from spreading at scale, &lt;a href="https://webaim.org/projects/million/"&gt;accessible components must be the default&lt;/a&gt;
 in your design system. AI should be used to feed these tokens into your
 UI, ensuring that even generated code stays within the “source of 
truth.”&lt;/li&gt;&lt;/ul&gt;&lt;h2 id="beyond-the-prompt"&gt;Beyond The Prompt&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/04/production-ready-becomes-design-deliverable-ux/#beyond-the-prompt"&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;div aria-hidden="true" class="c-friskies-box partners partners__lead partners__lead-place partners__external" data-amount="1" data-audience="non-subscriber" data-remove="true" data-rendered="true"&gt;&lt;ul&gt;&lt;a class="partners__native--smashing" href="https://www.smashingmagazine.com/contact/"&gt;
        &lt;picture&gt;
          &lt;source media="(max-width: 600px)"&gt;&lt;/source&gt;
          &lt;img alt="Advertise with Smashing Magazine" width="325" /&gt;
        &lt;/picture&gt;
      &lt;/a&gt;&lt;/ul&gt;&lt;/div&gt;&lt;p&gt;The industry is currently in a state of “AI Infatuation,” but the pendulum will eventually swing back toward quality.&lt;/p&gt;&lt;blockquote class="pull-quote"&gt;&lt;p&gt;&lt;a aria-label="Share on Twitter" class="pull-quote__link" href="https://twitter.com/share?text=%0aThe%20UX%20designer%e2%80%99s%20nightmare%20ends%20when%20we%20stop%20trying%20to%20compete%20with%20AI%20tools%20at%20what%20they%20do%20best%20%28generating%20syntax%29%20and%20keep%20our%20focus%20on%20what%20they%20cannot%20do%20%28understanding%20human%20complexity%29.%0a&amp;amp;url=https://smashingmagazine.com%2f2026%2f04%2fproduction-ready-becomes-design-deliverable-ux%2f"&gt;The
 UX designer’s nightmare ends when we stop trying to compete with AI 
tools at what they do best (generating syntax) and keep our focus on 
what they cannot do (understanding human complexity).&lt;/a&gt;&lt;/p&gt;&lt;div class="pull-quote__quotation"&gt;&lt;div class="pull-quote__bg"&gt;&lt;span class="pull-quote__symbol"&gt;“&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;p&gt;Businesses
 that prioritise “designer-shipped code” without engineering oversight 
will eventually face a reckoning of technical debt, security breaches, 
and accessibility lawsuits. The designers who thrive in 2026 and beyond 
will be those who refuse to be “prompt operators” and instead position 
themselves as the &lt;strong&gt;guardians of the user experience&lt;/strong&gt;. This is the perfect outcome for experienced designers and for the industry.&lt;/p&gt;&lt;p&gt;Our
 value has always been our ability to advocate for the human on the 
other side of the screen. We must use AI to augment our design thinking,
 allowing us to test more ideas and iterate faster, but we must never 
let it replace the specialised engineering expertise that ensures our 
designs technically &lt;em&gt;work&lt;/em&gt; for everyone.&lt;/p&gt;&lt;h3 id="summary-checklist-for-ux-designers"&gt;Summary Checklist for UX Designers&amp;nbsp;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Work Together.&lt;/strong&gt;&lt;br /&gt;Use
 AI-made code as a starting point to talk with your developers. Don’t 
use it as a shortcut to avoid working with them. Ask them to help you 
with prompts for code creation for the best outcomes.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Understand the “Why”.&lt;/strong&gt;&lt;br /&gt;Never submit code you don’t understand. If you can’t explain how the AI-generated logic works, don’t include it in your work.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Build for Everyone.&lt;/strong&gt;&lt;br /&gt;Good
 design is more than just looks. Use AI to check if your code works for 
people using screen readers or keyboards, not just to make things look 
pretty.&lt;/li&gt;&lt;/ul&gt;</description><link>http://honeyvig.blogspot.com/2026/04/the-ux-designers-nightmare-when_01127696254.html</link><author>noreply@blogger.com (H)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-9165069509664255576.post-257180627373482435</guid><pubDate>Wed, 29 Apr 2026 11:28:00 +0000</pubDate><atom:updated>2026-05-05T05:18:08.523-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">advice</category><category domain="http://www.blogger.com/atom/ns#">E-Commerce</category><category domain="http://www.blogger.com/atom/ns#">Opinion</category><category domain="http://www.blogger.com/atom/ns#">suggestion</category><title>Shopify For Everyone!How Brands Use AI: Real-World Examples and Strategies Reference</title><description>&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="reader-author-info__container"&gt;&lt;div class="mt4"&gt;&lt;time class="text-body-small-open t-black--light"&gt;
                    &lt;/time&gt;
                  &lt;/div&gt;
                &lt;/div&gt;


                
    &lt;div data-scaffold-immersive-reader-content=""&gt;
      
                  
    &lt;div&gt;
      &lt;div class="reader-article-content reader-article-content--content-blocks" dir="ltr"&gt;
          

      &lt;div class="reader-content-blocks-container"&gt;

            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember62"&gt;
      Shopify is good. It is not universal. What follows is for everyone the pitch keeps missing.
    &lt;/p&gt;

  






            
        
    &lt;h3 class="ember-view reader-text-block__heading-3" id="ember63"&gt;
      Shopify is perfect for you
    &lt;/h3&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember64"&gt;
      You can't go to a commerce event in 2026 and avoid the pitch. No, 
not a Commerce event. The other one. The category, not the company. Stay
 with me. You can't open LinkedIn. You can't watch a Shopify demo 
without it landing in the first three slides.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember65"&gt;
      Shopify is perfect for you.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember66"&gt;
      It doesn't matter who "you" are. B2B distributor with company 
hierarchies and negotiated pricing? Shopify. European DTC brand running 
B2C and wholesale on the same SKUs? Shopify. Headless team trying to 
build the agent-native commerce stack? Shopify Hydrogen. Bootstrapped 
developer with $40 a month to spend? Shopify. A creator selling 
services, products, and bookings out of one cart? Shopify. Heineken? 
Apparently not. They picked Medusa.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember67"&gt;
      The pitch never adjusts to the merchant. It adjusts to whoever is sponsoring the lunch.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember68"&gt;
      So let's adjust it.
    &lt;/p&gt;

  






            
        
    &lt;h3 class="ember-view reader-text-block__heading-3" id="ember69"&gt;
      The pitch is bigger than Shopify
    &lt;/h3&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember70"&gt;
      I went looking for a Shopify exec saying "Shopify is for 
everyone." I didn't find one. Shopify itself is more careful than the 
pitch its industry creates. Shopify Plus marketing segments by use case 
(B2B, omnichannel, DTC). Tobi Lütke at Editions 2025 talked about 
helping the merchants on Shopify do well, not about being right for 
every merchant on the planet.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember71"&gt;
      The universal pitch comes from somewhere else. It comes from 
agency partners with quotas. It comes from SEO posts like "Why Shopify 
Will Dominate eCommerce Growth in 2026," positioning Shopify as the 
"go-to choice for both global enterprise brands and direct-to-consumer 
creators" in one breath (Ayatas Infotech, 2026). It comes from posts 
like "The Future of Shopify: How the Platform Will Transform Online 
Selling in 2026," framing Shopify as a "Complete Business Operating 
System" for any merchant alive (Fourfoldtech, 2026).
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember72"&gt;
      That's the pitch I'm taking apart. Not Shopify the platform. The 
industry-default reflex that recommends Shopify before anyone has asked 
who the merchant is.
    &lt;/p&gt;

  






            
        
    &lt;h3 class="ember-view reader-text-block__heading-3" id="ember73"&gt;
      The Six Platforms Shopify Forgot To Mention
    &lt;/h3&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember74"&gt;
      Shopify is real. $378.4 billion in GMV across 5.6 million active 
stores (DigitalApplied 2026). Excellent at what it was built for. 
Nothing here is a hit piece.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember75"&gt;
      But "everyone" is doing a lot of work in the universal pitch.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember76"&gt;
      Stop asking "is Shopify good?" Start asking: who is this merchant,
 and what does the platform cost them in flexibility, ownership, and 
fit?
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember77"&gt;
      I asked that question across six platforms. Each one wins for a 
different merchant. Each one has been told Shopify is perfect for them. 
Each one has a better answer.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember78"&gt;
      I write this for the merchant in the audience who got told Shopify
 is perfect for them at NRF, ShopTalk, eTail, or some podcast last week 
and hasn't asked the question since. The merchant deserves a real 
comparison. The merchant deserves to know there are six other names in 
this conversation. The platforms deserve to be in it.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember79"&gt;
      I have written about my own paradox before. I built a Shopify app 
even after years of explaining the platform's limitations, because that 
is where the customers are (My Shopify Paradox, ACG, July 2025). The paradox is real. The pitch is the problem.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember80"&gt;
      Six because of time and space. The list could go longer 
(commercetools, Salesforce Commerce Cloud, Spryker, Saleor, Vendure, 
OroCommerce, PrestaShop, Centra). Each has its merchant. These six are 
where to start.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember81"&gt;
      Let's start with the one that just changed its name.
    &lt;/p&gt;

  






            
        
    &lt;h3 class="ember-view reader-text-block__heading-3" id="ember82"&gt;
      1. Commerce (formerly BigCommerce)
    &lt;/h3&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember83"&gt;
      The merchant: SaaS without the walled garden, with agentic commerce baked in.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember84"&gt;
      BigCommerce has a great product. Let me say that twice. 
BigCommerce has a great product. The platform ships an enterprise-grade 
SaaS that you can extend with Catalyst, Makeswift for visual editing, 
and Feedonomics for product feeds across Google, Meta, TikTok, and 
Amazon. Mountain Warehouse just launched a composable storefront on 
Catalyst with Vercel, Contentful, and Algolia (Commerce press, April 
2026). That's a real merchant doing real composable work without leaving
 the platform.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember85"&gt;
      Catalyst sidesteps a problem I wrote about before (The Headless Trap,
 ACG, August 2025). The framework is opinionated. The platform is 
opinionated. The merchant doesn't have to assemble both from scratch.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember86"&gt;
      The rebrand is the problem. In July 2025, BigCommerce announced it
 was becoming "Commerce" (Wikipedia). The ticker changed from BIGC to 
CMRC around August 1, 2025. Three product lines (BigCommerce, 
Feedonomics, Makeswift) now sit under one parent brand. CEO Travis Hess 
called it "a clear declaration" focused on "agentic commerce" 
(EcommerceNews EU, 2025). The agentic commerce read is right. The naming
 is muddled. Calling the company "Commerce" and the product 
"BigCommerce" might work in the long run. Maybe.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember87"&gt;
      Let's call BigCommerce BigCommerce.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember88"&gt;
      The product earned the rebrand. The rebrand hasn't earned the product yet.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember89"&gt;
      &lt;b&gt;Pro:&lt;/b&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;Open SaaS with real composable hosting and a feed manager (Feedonomics) that the rest of the category copies.&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;b&gt;Con:&lt;/b&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;The strategic message got diluted in the rename, and merchants are still figuring out what to call what.&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;b&gt;Real merchant:&lt;/b&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;Mountain Warehouse on Catalyst (April 2026).&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;b&gt;Agentic readiness:&lt;/b&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;Commerce
 Companion AI in admin, Feedonomics with Google Cloud Gemini for product
 enrichment, agent-enabled checkout work in the roadmap.&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;b&gt;Best for:&lt;/b&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;Mid-market
 merchants who want SaaS stability and composable flexibility without 
writing a headless storefront from scratch. Catalyst gives them the 
framework. Makeswift gives them visual editing on top, so non-developers
 can ship storefront changes. Feedonomics handles cross-channel feeds 
across Google, Meta, TikTok, and Amazon. They run multi-channel selling,
 they want headless without a full engineering team, and they are done 
with Shopify Plus telling them which composable extensions are allowed.
    &lt;/p&gt;

  






            
        
    &lt;h3 class="ember-view reader-text-block__heading-3" id="ember90"&gt;
      2. Shopware
    &lt;/h3&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember91"&gt;
      The merchant: complex B2B. Companies with hierarchies, sales reps,
 custom catalogs per customer, quoted pricing, and approval workflows. 
Shopware wins 54% of the deals it competes for in this category (per 
Shopware). DTC merchants run on it too, but B2B is the headline.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember92"&gt;
      The time is now for Shopware. You own your data. You don't rent it
 back from a SaaS company that decides one day to change your fees, your
 checkout, or your app permissions. You make any change you want, any 
customization you need, because the license lets you. You get support 
from a team that picks up the phone.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember93"&gt;
      Then there is the pricing. Shopify charges by volume. Transaction 
fees on every sale. App store fees that compound. Plus tiers that scale 
with revenue. The bigger the merchant, the bigger the bill. Shopware 
caps the platform cost through licensing. The busier the merchant, the 
better the unit economics. That is not a small thing for a brand doing 
$20M, $50M, or $200M GMV. When the merchant grows, the merchant keeps 
the upside.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember94"&gt;
      Then there's the funding story. PayPal first invested in Shopware 
in February 2022 as part of a $100 million round with Carlyle Group 
(Shopware press release, 2022). In October 2025, PayPal increased its 
stake from 11% to roughly 41% by buying Carlyle's shares (EcommerceNews 
EU, 2025). PayPal is now Shopware's largest external shareholder. That 
isn't a partnership announcement. That's a payments company putting real
 ownership behind a platform built for merchants who want B2B, DTC, and 
ownership in one stack.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember95"&gt;
      The US momentum is the new story. Shopware North America reported 
300% year-over-year growth in the first half of 2025 (Shopware press, 
2025). Named US client wins included UPPAbaby, Good360, Eagle Crusher, 
BlueAlly, Noble, and Dynamic Team Sports. New US partnerships landed 
with Klaviyo, BlueSnap, PayTrace, Webscale, and Liquid Web. Shopware 
hosted Shoptoberfest in NYC in September 2025 to celebrate the company's
 25th anniversary on US soil (PR Newswire, 2025-09-16). Store Leads data
 showed Shopware net-gained 2,995 merchants from competitive platforms 
over the prior 90 days (Store Leads, Q1 2026).
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember96"&gt;
      Shopware is closing deals and making waves in the US market. The 
agencies told you Shopify Plus could do B2B. Shopify Plus does company 
logins. Shopware does company hierarchies, native quoting, sales rep 
tools, and custom catalogs per customer. That's B2B. The other thing is a
 feature flag.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember97"&gt;
      &lt;b&gt;Pro:&lt;/b&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;Native 
B2B depth (54% win rate per Shopware), licensing model that doesn't tax 
growth, US momentum backed by 41% PayPal ownership.&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;b&gt;Con:&lt;/b&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;The brand is still earning US recognition, which means agencies still default to Shopify Plus on first reference.&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;b&gt;Real merchant:&lt;/b&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;Eagle Crusher (heavy equipment B2B) and UPPAbaby (premium DTC), both US.&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;b&gt;Agentic readiness:&lt;/b&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;Shopware AI Copilot for product data, content, and customer service.&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;b&gt;Best for:&lt;/b&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;Mid-market
 and enterprise merchants running complex B2B. Company hierarchies, 
sales rep accounts, custom catalogs per customer, quoted pricing, 
approval workflows. Shopware closes 54% of the deals it competes for in 
this category (per Shopware). DTC merchants run on it too, but B2B is 
the headline. They want ownership over rent, customization their lawyer 
can approve, a team that picks up the phone, and a pricing model that 
doesn't punish them for growing. Increasingly US-based: 300% YoY North 
American growth, named wins like Eagle Crusher and UPPAbaby.
    &lt;/p&gt;

  






            
        
    &lt;h3 class="ember-view reader-text-block__heading-3" id="ember98"&gt;
      3. Wix
    &lt;/h3&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember99"&gt;
      The merchant: the creator whose storefront IS the brand presence.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember100"&gt;
      Wix is the new up-and-comer, and the AI tools they are adding are 
fantastic. You get world-class content and commerce in one easy-to-use 
package.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember101"&gt;
      We underestimate Wix because it sells to people we don't talk to 
at conferences. The creator running services, products, and bookings 
doesn't need Plus, doesn't want headless, and has been told for a decade
 that Shopify is the answer to a question they never asked. Wix shipped 
one of the most credible AI site builders in the category. The Wix AI 
Site Generator writes product descriptions, generates images, designs 
layouts, fills in SEO and meta tags, and runs your ad copy (EasyApps 
comparison, 2026). Inside the same dashboard. Without an app store tax.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember102"&gt;
      The thing Wix gets right is the merchant nobody else builds for: 
the brand whose content and commerce are the same business. Bookings, 
services, products, blog, email, all in one cart, all in one editor. 
Shopify will sell you Plus to bolt that together. Wix ships it as the 
default. 1,000 product variants per item versus Shopify's 100. 6+ option
 sets versus Shopify's 3. 900-plus templates with full drag-and-drop 
(EasyApps 2026). Built-in Semrush integration and ad management without 
paying for a higher tier.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember103"&gt;
      For the merchant whose audience IS the storefront, that isn't a feature gap. That's a category.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember104"&gt;
      I made this case before (&lt;a class="IwhKTCKzBPIgoVvQoPGKwfehndPXUYtwTs" data-test-app-aware-link="" href="https://www.linkedin.com/pulse/dont-underestimate-wix-commerce-brent-w-peterson-j1uoc/" tabindex="0" target="_self"&gt;Don't Underestimate Wix Commerce&lt;/a&gt;, ACG, October 2025). The case has only gotten stronger.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember105"&gt;
      &lt;b&gt;Pro:&lt;/b&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;Native bookings, services, and products in one cart with AI tooling baked into the editor.&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;b&gt;Con:&lt;/b&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;Less credible the higher you go in catalog complexity and headless ambition.&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;b&gt;Real merchant:&lt;/b&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;Wix's
 strength is in the long tail of creator and service brands rather than 
headline DTC names, which is itself part of the story.&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;b&gt;Agentic readiness:&lt;/b&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;Wix AI Site Generator handles content, layout, SEO, and ad creative end-to-end.&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;b&gt;Best for:&lt;/b&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;Creators,
 service-led brands, and small businesses where the storefront IS the 
brand presence. Yoga studios. Photographers. Coaches. Boutique 
consultancies selling services, products, and bookings in one cart. They
 want AI to write product descriptions, design layouts, and run their ad
 copy without paying $2,500 a month for Shopify Plus. They are not 
building headless. They want one editor and one tool.
    &lt;/p&gt;

  






            
        
    &lt;h3 class="ember-view reader-text-block__heading-3" id="ember106"&gt;
      4. Hyvä Commerce on Mage-OS
    &lt;/h3&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember107"&gt;
      The merchant: done renting their stack.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember108"&gt;
      Magento. Adobe. Let's face it. Adobe does not care about Magento. 
They see it as a threat. Hello, Magento IS Adobe. They should be gaining
 sites TO Adobe FROM Magento. It's the perfect funnel. Instead, Adobe 
sees Magento as competition.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember109"&gt;
      The lack of focus on commerce shows up in poor support, poor 
performance, and no real roadmap. When I say no real roadmap, I 
challenge anyone from Adobe to show me their commerce roadmap. No 
feature ever. No feature planning. Nothing new. Did I mention nothing 
new?
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember110"&gt;
      I got to a lot of Magento conferences. Same slides. No new 
commerce features. No new commerce features. No new commerce features.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember111"&gt;
      I will not pull punches on Adobe.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember112"&gt;
      One warning before we leave Adobe. The European Magento community 
sees Hyvä shipping, sees Mage-OS shipping, and assumes the US Magento 
ecosystem looks the same. It does not. Adobe stopped marketing Magento 
in the US. Are they signing new US agencies? I doubt it. The US Magento 
community has been left to fend for itself while Adobe's attention went 
to AEM and AEP. That's not a Hyvä problem. That's not a Mage-OS problem.
 That's an Adobe problem. And the US merchant pays for it.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember113"&gt;
      Hyvä is going gangbusters. New products coming out all the time, 
pushing performance, building everything Adobe Commerce could be but 
isn't. Hyvä Themes replaced Magento's Knockout.js with Alpine.js and 
Tailwind, and agencies report 30 to 50% faster builds (Hyvä 2025 product
 update). 6,400 live stores already run Hyvä (Hyvä 2025 product update).
 On November 10, 2025, Hyvä Themes went open source under OSL3 and AFL3,
 announced at Meet Magento Netherlands (iOvista, 2025-11-10). Hyvä 
Commerce launched the same year as a separate product built to extend 
Magento Open Source for ops, scalability, and merchant experience (Fluid
 Commerce, 2025).
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember114"&gt;
      Mage-OS is the foundation. A community-governed, 
upstream-compatible fork of Magento Open Source, run by the independent 
Mage-OS Association rather than the Adobe-controlled Magento Association
 (Mage-OS, ongoing). The fork exists because Adobe stopped investing. 
Adobe Commerce starts at roughly $22,000 per year (Web-vision, 2025). 
Mage-OS is free.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember115"&gt;
      The merchant who picks Hyvä on Mage-OS is done renting. They want 
code ownership, performance, and a community that ships. They got tired 
of waiting for Adobe to come back. So they built without Adobe.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember116"&gt;
      &lt;b&gt;Pro:&lt;/b&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;Open-source ownership, fastest frontend in the category, governed by a community that ships in the open.&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;b&gt;Con:&lt;/b&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;Requires a development team. This isn't a "set it up in 30 minutes" platform.&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;b&gt;Real merchant:&lt;/b&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;6,400+ live Hyvä-powered stores across the Magento ecosystem.&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;b&gt;Agentic readiness:&lt;/b&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;Open architecture means any agentic layer can be wired in. Nothing is gated by a vendor.&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;b&gt;Best for:&lt;/b&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;Merchants
 who picked Magento years ago, watched Adobe stop shipping commerce 
features, and decided to keep their stack instead of starting over. They
 want code ownership, not a SaaS subscription. They want the fastest 
frontend in the category. They want a community-governed platform where 
the roadmap is in the open. They have a development team or a partner 
agency who can run it.
    &lt;/p&gt;

  






            
        
    &lt;h3 class="ember-view reader-text-block__heading-3" id="ember117"&gt;
      5. MedusaJS
    &lt;/h3&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember118"&gt;
      The merchant: a team building commerce around the agent, not bolting an agent onto commerce.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember119"&gt;
      I really like what Medusa is doing. The homepage tagline tells you
 the whole story: "A Commerce Platform for Developers and Agents" (&lt;a class="IwhKTCKzBPIgoVvQoPGKwfehndPXUYtwTs" data-test-app-aware-link="" href="http://medusajs.com" tabindex="0" target="_self"&gt;medusajs.com&lt;/a&gt;).
 Not a marketing line bolted onto a SaaS product. The architecture 
itself was rebuilt around how developers and AI agents work.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember120"&gt;
      Bloom lets you chat to build. Agent Skills are baked into the 
development experience. One Medusa case study reports 80% cost savings 
on an AI-powered email-to-order workflow (&lt;a class="IwhKTCKzBPIgoVvQoPGKwfehndPXUYtwTs" data-test-app-aware-link="" href="http://medusajs.com" tabindex="0" target="_self"&gt;medusajs.com&lt;/a&gt;). That isn't an integration. That's the product.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember121"&gt;
      The proof is on the homepage. Heineken. EightSleep. Mitsubishi 
Motors. None of those brands picked Medusa because it's free or easy. 
They picked it because their teams wanted commerce built around how 
their teams already work. With $29 entry pricing and no GMV tax, the 
economics aren't the story either. The story is the architecture and the
 team behind it.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember122"&gt;
      I went deeper on Medusa in (A Look at Medusa Commerce, ACG, December 2025). What stood out then was the architecture. What stands out now is the merchant proof.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember123"&gt;
      Every European platform trying to enter the US market, including 
Medusa, hits the same wall. Shopify is the gorilla in the room. Shopware
 is climbing. 300% year-over-year growth, named US wins, real 
partnerships. Medusa is earlier in that climb. They need boots on the 
ground in the US. They need US advocates willing to talk about what 
they're doing well in the markets where Shopify is the default answer. 
The platforms are good. The marketing fight against Shopify in the US is
 the harder problem.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember124"&gt;
      The merchant who picks Medusa is a developer-led team that read 
"agentic commerce" and asked what commerce could look like if you 
started from the agent, instead of asking how you bolt an agent onto 
Shopify.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember125"&gt;
      &lt;b&gt;Pro:&lt;/b&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;Architecture built around developers and agents, with named brand proof on the homepage.&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;b&gt;Con:&lt;/b&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;The US market presence is still building. The community is smaller than Shopify's app ecosystem.&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;b&gt;Real merchant:&lt;/b&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;Heineken, EightSleep, Mitsubishi Motors (&lt;a class="IwhKTCKzBPIgoVvQoPGKwfehndPXUYtwTs" data-test-app-aware-link="" href="http://medusajs.com" tabindex="0" target="_self"&gt;medusajs.com&lt;/a&gt;).&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;b&gt;Agentic readiness:&lt;/b&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;This is the platform where "agentic" isn't a marketing layer. It's the design center.&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;b&gt;Best for:&lt;/b&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;Developer-led
 DTC brands who read "agentic commerce" as an architecture decision, not
 a marketing slide. They have a TypeScript team. They want an 
open-source platform that ships fast and has Heineken on the homepage. 
They want commerce APIs an agent can call directly, not a proprietary 
checkout SDK. They want $29-a-month entry pricing with no GMV tax. They 
are building the next-generation stack and they want a platform doing 
the same.
    &lt;/p&gt;

  






            
        
    &lt;h3 class="ember-view reader-text-block__heading-3" id="ember126"&gt;
      6. WooCommerce
    &lt;/h3&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember127"&gt;
      The merchant: the audience-first brand where content built the demand.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember128"&gt;
      WooCommerce is the most-deployed commerce platform on the open 
web. 4.7 million active stores. 18 to 21% global share by 
share-of-websites (DigitalApplied 2026). And it's the platform Shopify 
ignores hardest. Why? Three reasons that matter.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember129"&gt;
      First, the migration goes both ways. 9,195 stores moved from 
WooCommerce to Shopify in the last measurement period. 7,566 went the 
other direction, Shopify to WooCommerce (DigitalApplied 2026). That's 
not a funnel into Shopify. That's a swap. Shopify doesn't draw attention
 to a flow that runs both ways.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember130"&gt;
      Second, the WooCommerce merchant isn't the Shopify merchant. 
Shopify sells "store first, content later." The Woo merchant built the 
audience first and added the cart when the audience was ready to buy. 
The sales motion doesn't translate. The pitch doesn't land. Shopify's 
marketing budget can't reach a merchant whose store is a checkout button
 on a blog they've been writing for ten years.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember131"&gt;
      Third, the plugin moat is unbeatable. 60,000-plus WordPress 
plugins, any niche use case has a Woo extension that someone built and 
maintains (Salesforce 2026, generally accepted&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;a class="IwhKTCKzBPIgoVvQoPGKwfehndPXUYtwTs" data-test-app-aware-link="" href="http://WordPress.org" tabindex="0" target="_self"&gt;WordPress.org&lt;/a&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;plugin
 directory size). Shopify's app store can't match that breadth, and the 
breadth IS the lock-in. Once a Woo store has fifteen plugins solving 
fifteen specific problems, it isn't migrating anywhere.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember132"&gt;
      WooCommerce is open source. Free. Bolts onto WordPress. You can run it on&lt;span class="white-space-pre"&gt; &lt;/span&gt;WordPress.com,
 on any managed WordPress host (Pressable, Kinsta, WP Engine, Hostinger,
 Bluehost, Cloudways), or on your own infrastructure. The optionality is
 the point. Shopify charges by the seat. WooCommerce charges by the 
choice you already made when you picked WordPress.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember133"&gt;
      The merchant who picks WooCommerce is the audience-first brand. 
The publisher, the creator, the ten-year blogger, the membership site, 
the community. Their content built the demand. The cart just collects on
 it.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember134"&gt;
      &lt;b&gt;Pro:&lt;/b&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;Open-source, biggest plugin ecosystem on the web, owned by Automattic (not running out of runway).&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;b&gt;Con:&lt;/b&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;You own the hosting, security, and maintenance choices. That's freedom and that's responsibility.&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;b&gt;Real merchant:&lt;/b&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;4.7 million stores running it, including the bidirectional migration crowd.&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;b&gt;Agentic readiness:&lt;/b&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;WordPress's
 plugin model means any AI agent layer can plug in. The ecosystem is 
moving on this faster than the headlines suggest.&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;b&gt;Best for:&lt;/b&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;Audience-first
 brands. The publisher who built ten years of newsletter readers and 
wants to sell them something. The blogger whose audience is bigger than 
their store. The membership site adding paid courses. The community 
building a product around their already-loyal followers. They are not 
picking commerce-first. They are picking content-first, and the cart is 
the natural extension.
    &lt;/p&gt;

  






            
        
    &lt;h3 class="ember-view reader-text-block__heading-3" id="ember135"&gt;
      So what?
    &lt;/h3&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember136"&gt;
      The pitch is broken. The platforms aren't.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember137"&gt;
      Shopify is good. Shopify is not universal. Anyone selling you 
"Shopify is perfect for you" is selling Shopify. They are not solving 
for you. The right question for any merchant is simple. Who is this 
merchant? What does the platform cost them in flexibility, ownership, 
and fit?
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember138"&gt;
      If you're a B2B distributor with company hierarchies, the answer 
is Shopware or Adobe Commerce or Hyvä on Mage-OS, depending on whether 
you want SaaS, enterprise rental, or ownership.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember139"&gt;
      If you're a creator running services and products in one cart, the answer is Wix.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember140"&gt;
      If you're a developer-led DTC brand building the agent-native commerce stack, the answer is Medusa.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember141"&gt;
      If you're a publisher whose audience built the demand, the answer is WooCommerce.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember142"&gt;
      If you're a mid-market merchant who wants SaaS without the walled 
garden, the answer is BigCommerce. Sorry. Commerce. The product is 
BigCommerce. The company is Commerce. We'll figure that one out.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember143"&gt;
      If you're done renting your stack, the answer is Hyvä on Mage-OS.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember144"&gt;
      The platform is downstream of the merchant. Pick the merchant first. Pick the platform second.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember145"&gt;
      The next time you hear "Shopify is perfect for you" at a panel, 
ask the speaker who they're selling to. If they can't answer that 
without saying "everyone," they're not selling you. They're selling the 
sponsor.
    &lt;/p&gt;

  






            
        
    &lt;h3 class="ember-view reader-text-block__heading-3" id="ember146"&gt;
      Question for you
    &lt;/h3&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember147"&gt;
      Which of the six would you build on next, and what told you Shopify wasn't the right pick?
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember148"&gt;
      I read every comment.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember149"&gt;
      One more question to sit with.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember150"&gt;
      Is the world really better with only one commerce platform?
    &lt;/p&gt;&lt;hr class="reader-divider-block__horizontal-rule" /&gt;&lt;p&gt;More businesses are discovering that AI’s value truly emerges when it augments human creativity and capability rather than completely replacing it.&lt;br /&gt;Reference: https://www.shopify.com/blog/how-brands-use-ai?Artificial intelligence has moved from promise to practice in record time—and business leaders are racing to harness it. McKinsey reports that 92% of companies plan to increase their AI investments over the next three years. At the same time, early adopters are already seeing meaningful improvements: Among small businesses currently using AI, 80% report increased efficiency, and nearly half say that AI has improved their data-driven decision-making, according to Goldman Sachs.&lt;br /&gt;&lt;br /&gt;Yet, AI isn’t a magic bullet. It takes careful scoping and thoughtful implementation to deliver value. AI isn’t a replacement for the creativity, judgment, or intuition that small businesses rely on. Instead, it’s expanding what small teams can accomplish: According to a 2025 Shopify survey, 69% of business owners who use AI tools do so to generate content. Other popular use cases include helping with data analysis and insights (32%), improving customer service quality (29%), and assisting with product development (23%).&lt;br /&gt;&lt;br /&gt;More businesses are discovering that AI’s value truly emerges when it augments human creativity and capability rather than completely replacing it. These are the ways savvy businesses are putting AI to work—and where they’re finding the most success.&lt;br /&gt;Reference: https://www.shopify.com/blog/how-brands-use-ai?Democratizing data science for smarter campaigns&lt;br /&gt;&lt;br /&gt;What once required focus groups, surveys, and weeks of analysis can now happen in a matter of minutes with AI. Small businesses are increasingly using AI for market research tasks like analyzing customer reviews, social conversations, and search behavior, uncovering emerging needs before competitors can respond.&lt;br /&gt;&lt;br /&gt;Jones Road Beauty uses tools like OpenAI’s Deep Research to analyze thousands of product reviews, Reddit threads, and YouTube comments. From that analysis, the clean-beauty brand’s team identified five real-world personas—such as busy parents and frequent travelers. Those insights informed its Just Enough tinted moisturizer campaign, helping the team refine messaging, select appropriate models, and shape the overall creative direction.&lt;br /&gt;&lt;br /&gt;AI-powered analysis isn’t just speeding up data analysis—it’s making it available to anyone at the company. Wallet and accessories brand Ridge is using AI to remove internal bottlenecks that used to slow data-driven decision-making. “We have a data warehouse and all these Shopify reports,” says Ridge CEO Sean Frank. “Instead of doing anything manually, I can take a screenshot, drop it into ChatGPT, and it runs the analysis for me. My entire team can operate like data scientists.” Rather than waiting hours or days for a specialist to crunch numbers, anyone on the team can pull their own insights instantly.&lt;br /&gt;&lt;br /&gt;Your 24/7 Shopify expert is here&lt;br /&gt;&lt;br /&gt;Do data analysis without leaving your admin with Sidekick. Learn how your AI assistant makes it easier to start, run and grow your business on Shopify.&lt;br /&gt;Meet Sidekick&lt;br /&gt;&lt;br /&gt;These examples illustrate a broader shift: AI is giving small teams the analytical horsepower of larger organizations. By lowering the barrier to data analysis, brands can move faster, experiment more often, and build campaigns rooted in what customers actually think and do.&lt;br /&gt;Building personalized products&lt;br /&gt;&lt;br /&gt;For small businesses with limited engineering resources, launching a new product can be costly and time-consuming. AI is shifting that calculus. By accelerating research, content generation, and user-testing cycles, AI enables teams to bring new digital offerings to market with unprecedented speed. In many cases, it isn’t just accelerating development, but making entirely new categories of personalized, adaptive products possible.&lt;br /&gt;&lt;br /&gt;Get your free product development worksheet&lt;br /&gt;&lt;br /&gt;Create a product that meets your customers’ needs with our easy-to-follow, 7-step product development worksheet.&lt;br /&gt;Learn more&lt;br /&gt;&lt;br /&gt;Loftie, a wellness company that designs sleep products, used AI to develop and launch the Loftie Rest app, a digital companion to its signature alarm clock. The app broadened Loftie’s reach and unlocked a new revenue stream, creating a subscription business from the ground up that now has roughly 15,000 members. “We wouldn’t have released this product without AI,” founder and CEO Matthew Hassett says. “It was the initial seed of what our subscription app became.”&lt;br /&gt;&lt;br /&gt;Personalized content is the backbone of the Rest app, beginning with Storymaker, which generates tailored bedtime stories using a brief survey and adjustable voice profiles powered by OpenAI and Eleven Labs. Extending personalization even further, Loftie’s Night School feature analyzes correlations between users’ Apple Health data, screen time habits, alarm settings, and self-reported sleep quality. When patterns emerge—like midnight scrolling leading to poor sleep—the tool recommends habit changes or prompts users to block distracting apps. “We use AI to look at patterns and make proactive suggestions to help you ditch your phone at night,” Matthew says.&lt;br /&gt;&lt;br /&gt;At every stage, Loftie pairs AI insights with human-created content, from educational modules to meditation flows. AI determines what a user needs, while humans help craft what is delivered. The result is a digital product that continuously adapts while maintaining a distinctly human tone, something that would have been prohibitively complex to build without AI.&lt;br /&gt;Scaling ad creation and testing&lt;br /&gt;&lt;br /&gt;Scaling creative output is becoming an essential part of a strong paid advertising strategy. For success, brands need an increasing number of ad variations—often more than a creative team can realistically produce on its own.&lt;br /&gt;&lt;br /&gt;Ridge is using AI to close that gap. It created a custom GPT trained on its best-performing ads, then connected it to automation tools that generate hundreds of new static assets each day. “We’ve built a static ad factory,” says Sean. “I can get 500 ads a day—no hands on keyboards.”&amp;nbsp;&lt;br /&gt;&lt;br /&gt;These assets flow into a shared drive for review, but most won’t make it into rotation. And that’s OK; the point is volume. “Out of those 500, 450 are horrible,” Sean notes. “But the top 10% are between five out of 10 and seven out of 10. They’ll get spend behind them.” The brand plans to extend this process to video next, generating more hooks and variations for testing.&lt;br /&gt;&lt;br /&gt;AI is not replacing Ridge’s creative team. The company’s highest-performing ads still come from the human design team, which consistently produces 10-out-of-10 winners. AI just enables more concepts, more iterations, and more opportunities for platforms like Facebook to match the right ad to the right person at the right time.&lt;br /&gt;&lt;br /&gt;Reach customers everywhere they are with Shopify&lt;br /&gt;&lt;br /&gt;Shopify comes with powerful tools that help you promote and sell products on Facebook, Instagram, TikTok, Google, and YouTube from one back office. Make sales on multiple channels and manage everything from Shopify.&lt;br /&gt;Explore Shopify’s sales channels&lt;br /&gt;&lt;br /&gt;“The future of advertising is just shots on goal,” explains Sean. “What you see and like is going to be totally different from what I see and like.” By pairing human-crafted assets with high-volume AI-generated variations, Ridge can scale experimentation far beyond what manual efforts would allow—turning its paid strategy into a continuous, data-driven loop of testing and refinement.&amp;nbsp;&lt;br /&gt;Improving customer service&lt;br /&gt;&lt;br /&gt;Early AI tools like chatbots and interactive voice response (IVR) were a natural fit for repetitive use cases (like “Where’s my order?” and “What are your hours?”). This makes customer service one of the most mature applications of AI in small businesses. However, the stakes of balancing human and machine intervention remain high. A 2024 study from Acquire Intelligence found that just one bad AI-assisted support experience would make 70% of consumers consider taking their business elsewhere.&lt;br /&gt;&lt;br /&gt;At Loftie, AI agents now answer over half of incoming support emails. “It’s difficult to standardize responses across human agents—AI can be much more reliable,” Matthew says. “It’s answered the same question 1,000 times before.” The team also uses AI to surface trends from what Matthew calls a “graveyard of data,” turning thousands of customer interactions into insights that inform product and experience improvements. “I’m honestly surprised when brands are reticent to adopt AI for customer service,” he notes.&lt;br /&gt;&lt;br /&gt;Ridge has seen similar benefits. “Customer service is a super easy use case,” Sean explains. “Around 60% of our tickets are being answered by AI.” The company has also seen a 10% to 20% lift in customer satisfaction scores over human-only workflows. “Customers love talking to the AI,” he adds. “It’s faster, quicker, more accurate.”&lt;br /&gt;&lt;br /&gt;These improvements are driven by a shift from rule-based chatbots to agentic AI—tools that can understand intent, reference past interactions, access customer data, and take simple actions like processing refunds or replacing items. Once limited to large enterprises, agentic AI is accessible today via tools like Zendesk and HubSpot.&lt;br /&gt;&lt;br /&gt;When implemented thoughtfully—and understanding when to escalate emotional issues and complex problems to a human agent—AI expands what teams can handle without sacrificing quality. Routine questions are resolved quickly and consistently, and human agents can spend more time on the conversations that matter most.&lt;br /&gt;&lt;br /&gt;As AI continues to evolve, the opportunity for small businesses will come from this kind of selective adoption: using AI where it elevates human capabilities and keeping people at the center of the work that defines the brand.&lt;/p&gt;

  






      &lt;/div&gt;
  
      &lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description><link>http://honeyvig.blogspot.com/2026/04/shopify-for-everyone.html</link><author>noreply@blogger.com (H)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-9165069509664255576.post-4339684066322337230</guid><pubDate>Wed, 29 Apr 2026 07:02:00 +0000</pubDate><atom:updated>2026-04-29T00:02:00.115-07:00</atom:updated><title>The Site-Search Paradox: Why The Big Box Always Wins</title><description>&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="c-garfield-summary"&gt;&lt;section aria-label="Quick summary" class="article__summary"&gt;Success
 in modern UX isn’t about having the most content. It’s about having the
 most findable content. Yet even with more data and better tools than 
ever, internal search often fails, leaving users to rely on global 
search engines to find a single page on a local site. Why does the “Big 
Box” still win, and how can we bring users back?&lt;/section&gt;&lt;/div&gt;&lt;p&gt;In 
the early days of the web, the search bar was a luxury, added to a site 
once it became “too big” to navigate by clicking. We treated it like an 
index at the back of a book: a literal, alphabetical list of words that 
pointed to specific pages. If you typed the exact word the author used, 
you found what you needed. If you didn’t, you were met with a “0 Results
 Found” screen that felt like a digital dead end.&lt;/p&gt;&lt;p&gt;Twenty-five 
years later, we are still building search bars that act like 1990s index
 cards, even though the humans using them have been fundamentally 
rewired. Today, when a user lands on your site and can’t find what they 
need in the global navigation within seconds, they don’t try to learn 
your taxonomy. They head for the search box. But if that box fails them,
 and demands they use &lt;em&gt;your&lt;/em&gt; specific brand vocabulary, or 
punishes them for a typo, they do something that should keep every UX 
designer awake at night. They leave your site, go to Google, and type &lt;strong&gt;site:yourwebsite.com [query]&lt;/strong&gt;.
 Or, worse still, they just type in their query and end up on a 
competitor’s website. I personally use Google over a site’s search 
nearly every time.&lt;/p&gt;&lt;p&gt;This is the &lt;strong&gt;Site-Search Paradox&lt;/strong&gt;.
 In an era where we have more data and better tools than ever, our 
internal search experiences are often so poor that users prefer to use a
 trillion-dollar global search engine to find a single page on a local 
site. As Information Architects and UX designers, we have to ask, why 
does the “Big Box” win, and how can we take our users back?&lt;/p&gt;&lt;h2 id="the-syntax-tax-and-the-death-of-exact-match"&gt;The “Syntax Tax” And The Death Of Exact Match&lt;/h2&gt;&lt;p&gt;The primary reason site search fails is what I call the &lt;strong&gt;Syntax Tax&lt;/strong&gt;.
 This is the cognitive load we place on users when we require them to 
guess the exact string of characters we’ve used in our database.&lt;/p&gt;&lt;p&gt;Research by &lt;strong&gt;Origin Growth&lt;/strong&gt; on &lt;a href="https://www.origingrowth.co.uk/blog/search-vs-navigate-how-people-behave-on-websites-do-they-search-or-do-they-navigate/"&gt;&lt;strong&gt;Search vs Navigate&lt;/strong&gt;&lt;/a&gt; shows that roughly &lt;strong&gt;50% of users&lt;/strong&gt;
 go straight to the search bar upon landing on a site. For example, when
 a user types “sofa” into a furniture site that has categorised 
everything under “couches,” and the site returns nothing, the user 
doesn’t think, &lt;em&gt;“Ah, I should try a synonym.”&lt;/em&gt; They think, &lt;em&gt;“This site doesn’t have what I want.”&lt;/em&gt;&lt;/p&gt;&lt;p&gt;This is a failure of &lt;strong&gt;Information Architecture (IA)&lt;/strong&gt;. We’ve built our systems to match &lt;em&gt;strings&lt;/em&gt; (literal sequences of letters) rather than &lt;em&gt;things&lt;/em&gt; (the concepts behind the words). When we force users to match our internal vocabulary, we are taxing their brainpower.&lt;/p&gt;&lt;figure&gt;&lt;a href="https://files.smashing.media/articles/site-search-paradox-why-big-box-always-wins/1-keyword-semantic-search.jpg"&gt;&lt;img alt="Keyword Search vs Semantic Search" height="1000" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/site-search-paradox-why-big-box-always-wins/1-keyword-semantic-search.jpg" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;Keyword Search vs. Semantic Search. (Image source: &lt;a href="https://www.linkedin.com/posts/gerrid-smith_seo-digitalmarketing-marketing-activity-7349860105007341568-ipM_/"&gt;Gerrid Smith&lt;/a&gt;)&amp;nbsp;&lt;/figcaption&gt;&lt;/figure&gt;&lt;h2 id="why-google-wins-it-s-not-power-it-s-context"&gt;Why Google Wins: It’s Not Power, It’s Context&amp;nbsp;&lt;/h2&gt;&lt;p&gt;It
 is easy to throw our hands up and say, “We can’t compete with Google’s 
engineering.” But Google’s success isn’t just about raw power; it’s 
about &lt;strong&gt;contextual understanding&lt;/strong&gt;. While we often treat search as a technical utility, Google treats it as an IA challenge.&lt;/p&gt;&lt;p&gt;Data from the &lt;strong&gt;Baymard Institute&lt;/strong&gt; reveals that &lt;a href="https://baymard.com/blog/ecommerce-search-query-types"&gt;&lt;strong&gt;41% of e-commerce sites&lt;/strong&gt;&lt;/a&gt; fail to support even basic symbols or abbreviations, and this often leads to &lt;strong&gt;users&lt;/strong&gt; abandoning a site after a single failed search attempt. Google wins because it uses &lt;a href="https://www.ibm.com/think/topics/stemming-lemmatization#:~:text=How%20lemmatization%20works,syntactic%20function%20in%20the%20sentence."&gt;&lt;strong&gt;stemming and lemmatization&lt;/strong&gt;&lt;/a&gt;
 — IA techniques that recognize “running” and “ran” are the same intent.
 Most internal searches are “blind” to this context, treating “Running 
Shoe” and “Running Shoes” as entirely different entities.&lt;/p&gt;&lt;blockquote class="pull-quote"&gt;&lt;p&gt;&lt;a aria-label="Share on Twitter" class="pull-quote__link" href="https://twitter.com/share?text=%0aIf%20your%20site%20search%20can%e2%80%99t%20handle%20a%20simple%20plural%20or%20a%20common%20misspelling,%20you%20are%20effectively%20charging%20your%20users%20a%20tax%20for%20being%20human.%0a&amp;amp;url=https://smashingmagazine.com%2f2026%2f03%2fsite-search-paradox-why-big-box-always-wins%2f"&gt;If
 your site search can’t handle a simple plural or a common misspelling, 
you are effectively charging your users a tax for being human.&lt;/a&gt;&lt;/p&gt;&lt;div class="pull-quote__quotation"&gt;&lt;div class="pull-quote__bg"&gt;&lt;span class="pull-quote__symbol"&gt;“&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;figure&gt;&lt;a href="https://files.smashing.media/articles/site-search-paradox-why-big-box-always-wins/2-user-query-friction-user-flow.jpg"&gt;&lt;img alt="User Query Friction vs User Flow" height="800" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/site-search-paradox-why-big-box-always-wins/2-user-query-friction-user-flow.jpg" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;User Query Friction vs. User Flow. (Image source: Created with Gemini)&amp;nbsp;&lt;/figcaption&gt;&lt;/figure&gt;&lt;h2 id="the-ux-of-maybe-designing-for-probabilistic-results"&gt;The UX Of “Maybe”: Designing For Probabilistic Results&lt;/h2&gt;&lt;p&gt;In
 traditional IA, we think in binaries: A page is either in a category, 
or it isn’t. A search result is either a match or it isn’t. Modern 
search, which users now expect, is &lt;strong&gt;probabilistic&lt;/strong&gt;. It deals in “confidence levels.”&lt;/p&gt;&lt;p&gt;According to &lt;strong&gt;Forresters&lt;/strong&gt;, users who use search are &lt;a href="https://www.nosto.com/blog/ecommerce-site-search-statistics/#:~:text=Everyone’s%20searching%20for%20something%2C%20but,to%20convert%20and%20come%20back"&gt;&lt;strong&gt;2–3 times more likely to convert&lt;/strong&gt;&lt;/a&gt; than those who don’t, &lt;em&gt;if&lt;/em&gt; the search works. And &lt;a href="https://www.nosto.com/blog/ecommerce-site-search-statistics/#:~:text=Everyone’s%20searching%20for%20something%2C%20but,to%20convert%20and%20come%20back"&gt;&lt;strong&gt;80% of users&lt;/strong&gt;&lt;/a&gt; on e-commerce sites exit a site due to poor search results.&lt;/p&gt;&lt;p&gt;As designers, we rarely design for the middle ground. We design a “&lt;strong&gt;Results Found&lt;/strong&gt;” page and a “&lt;strong&gt;No Results&lt;/strong&gt;” page. We miss the most important state: &lt;strong&gt;The “Did You Mean?” State.&lt;/strong&gt;
 A well-designed search interface should provide “Fuzzy” matches. 
Instead of a cold “0 Results Found” screen, we should be using our 
metadata to say, &lt;em&gt;“We didn’t find that in ‘Electronics,’ but we found 3 matches in ‘Accessories’.”&lt;/em&gt; By designing for “Maybe,” we can keep the user in the flow.&lt;/p&gt;&lt;h2 id="case-study-the-cost-of-invisible-content"&gt;Case Study: The Cost Of “Invisible” Content&amp;nbsp;&lt;/h2&gt;&lt;p&gt;To
 understand why IA is the fuel for the search engine, we must look at 
how data is structured behind the scenes. In my 25 years of practice, 
I’ve seen that the “findability” of a page is directly tied to its 
structured metadata.&lt;/p&gt;&lt;p&gt;Consider a large-scale enterprise I worked 
with that had over 5,000 technical documents. Their internal search was 
returning irrelevant results because the “Title” tag of every document 
was the internal SKU number (e.g., “DOC-9928-X”) rather than the 
human-readable name.&lt;/p&gt;&lt;p&gt;By reviewing the search logs, we discovered 
that users were searching for “installation guide.” Because that phrase 
didn’t appear in the SKU-based title, the engine ignored the most 
relevant files. We implemented a &lt;strong&gt;Controlled Vocabulary&lt;/strong&gt;,
 which was a set of standardised terms that mapped SKUs to human 
language. Within three months, the “Exit Rate” from the search page 
dropped by 40%. This wasn’t an algorithmic fix; it was an IA fix. It 
proves that a search engine is only as good as the map we give it.&lt;/p&gt;&lt;div aria-hidden="true" class="c-friskies-box partners partners__lead partners__lead-place partners__external" data-amount="1" data-audience="non-subscriber" data-remove="true" data-rendered="true"&gt;&lt;ul&gt;&lt;a class="partners__native--smashing" href="https://www.smashingmagazine.com/contact/"&gt;
        &lt;picture&gt;
          &lt;source media="(max-width: 600px)"&gt;&lt;/source&gt;
          &lt;img alt="Advertise with Smashing Magazine" width="325" /&gt;
        &lt;/picture&gt;
      &lt;/a&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 id="the-internal-language-gap"&gt;The Internal Language Gap&amp;nbsp;&lt;/h2&gt;&lt;p&gt;Throughout
 my two decades in UX, I’ve noticed a recurring theme: internal teams 
often suffer from “The curse of knowledge.” We become so immersed in our
 own corporate vocabulary, or sometimes referred to as business jargon, 
that we forget the user doesn’t speak our language.&lt;/p&gt;&lt;p&gt;I once worked 
with a financial institution that was frustrated by high call volumes to
 their support centre. Users were complaining they couldn’t find “loan 
payoff” information on the site. When we looked at the search logs, 
“loan payoff” was the #1 searched term that resulted in zero hits.&lt;/p&gt;&lt;p&gt;Why?
 Because the institution’s IA team had labelled every relevant page 
under the formal term “Loan Release.” To the bank, a “payoff” was a 
process, but a “Loan Release” was the legal document that was the 
“thing” in the database. Because the search engine was looking for 
literal character strings, it refused to connect the user’s desperate 
need with the company’s official solution.&lt;/p&gt;&lt;p&gt;This is where the IA 
professional must act as a translator. By simply adding “loan payoff” as
 a hidden metadata keyword to the Loan Release pages, we solved a 
multi-million dollar support problem. We didn’t need a faster server; we
 needed &lt;strong&gt;a more empathetic taxonomy&lt;/strong&gt;.&lt;/p&gt;&lt;h2 id="the-4-step-site-search-audit-framework"&gt;The 4-step Site-search Audit Framework&lt;/h2&gt;&lt;p&gt;If
 you want to reclaim your search box from Google, you cannot simply “set
 it and forget it.” You must treat search as a living product. Here is 
the framework I use to audit and optimise search experiences:&lt;/p&gt;&lt;h3 id="phase-1-the-zero-result-audit"&gt;Phase 1: The “Zero-result” Audit&lt;/h3&gt;&lt;p&gt;Pull your search logs from the last 90 days. Filter for all queries that returned zero results. Group these into three buckets:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;True gaps&lt;/strong&gt;&lt;br /&gt;Content the user wants that you simply don’t have (a signal for your content strategy team).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Synonym gaps&lt;/strong&gt;&lt;br /&gt;Content you have, but described in words the user doesn’t use (e.g., “Sofa” vs “Couch”).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Format gaps&lt;/strong&gt;&lt;br /&gt;The user is looking for a “video” or “PDF,” but your search only indexes HTML text.&lt;/li&gt;&lt;/ul&gt;&lt;h3 id="phase-2-query-intent-mapping"&gt;Phase 2: Query Intent Mapping&lt;/h3&gt;&lt;p&gt;Analyse the &lt;em&gt;top 50&lt;/em&gt; most common queries. Are they &lt;strong&gt;Navigational&lt;/strong&gt; (looking for a specific page), &lt;strong&gt;Informational&lt;/strong&gt; (looking for “how to”), or &lt;strong&gt;Transactional&lt;/strong&gt;
 (looking for a specific product)? Your search UI should look different 
for each. A navigational search should “Quick-Link” the user directly to
 the destination, bypassing the results page entirely.&lt;/p&gt;&lt;h3 id="phase-3-the-fuzzy-matching-test"&gt;Phase 3: The “Fuzzy” Matching Test&lt;/h3&gt;&lt;p&gt;Intentionally
 mistype your top 10 products. Use plurals, common typos, and American 
vs. British English spellings (e.g., “Color” vs. “Colour”). If your 
search fails these tests, your engine lacks “stemming” support. This is a
 technical requirement you must advocate for to your engineering team.&lt;/p&gt;&lt;h3 id="phase-4-scoping-and-filtering-ux"&gt;Phase 4: Scoping And Filtering UX&lt;/h3&gt;&lt;p&gt;Look
 at your results page. Does it offer filters that actually make sense? 
If a user searches for “shoes,” they should see filters for &lt;em&gt;Size&lt;/em&gt; and &lt;em&gt;Colour&lt;/em&gt;. Generic filters can be as bad as no filters.&lt;/p&gt;&lt;h2 id="reclaiming-the-search-box-a-strategy-for-ia-professionals"&gt;Reclaiming The Search Box: A Strategy For IA Professionals&amp;nbsp;&lt;/h2&gt;&lt;p&gt;To stop the exodus to Google, we must move beyond the “Box” and look at the &lt;strong&gt;scaffolding&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Step A: Implement semantic scaffolding.&lt;/strong&gt;&lt;br /&gt;Don’t
 just return a list of links. Use your IA to provide context. If a user 
searches for a product, show them the product, but also show them the &lt;em&gt;manual&lt;/em&gt;, the &lt;em&gt;FAQs&lt;/em&gt;, and the &lt;em&gt;related parts&lt;/em&gt;. This “associative” search mimics how the human brain works and how Google operates.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Step B: Stop being a librarian, start being a concierge.&lt;/strong&gt;&lt;br /&gt;A
 librarian tells you exactly where the book is on the shelf. A concierge
 listens to what you want to achieve and gives you a recommendation. 
Your search bar should use predictive text not just to complete words, 
but to &lt;strong&gt;suggest intentions&lt;/strong&gt;.&lt;/p&gt;&lt;h2 id="using-a-google-powered-search-bar"&gt;Using A Google-powered Search Bar&lt;/h2&gt;&lt;p&gt;Using a “Google-powered” search bar, as seen on the &lt;strong&gt;University of Chicago&lt;/strong&gt;
 website, is essentially an admission that a site’s internal 
organisation has become too complex for its own navigation to handle. 
While it is a quick “fix” for massive institutions to ensure users find &lt;em&gt;something&lt;/em&gt;, it is generally a poor choice for businesses with deep content.&lt;/p&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://files.smashing.media/articles/site-search-paradox-why-big-box-always-wins/3-university-chicago-website.png"&gt;&lt;img alt="Example of a university website using Google-powered search." height="508" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/site-search-paradox-why-big-box-always-wins/3-university-chicago-website.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;Example of a university website using Google-powered search. (Source: &lt;a href="https://www.uchicago.edu/en"&gt;University of Chicago&lt;/a&gt;)&amp;nbsp;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;By
 delegating the search to Google, you surrender the user experience to 
an outside algorithm. You lose the ability to promote specific products,
 you expose your users to third-party ads, and you train your customers 
to leave your ecosystem the moment they need help. For a business, 
search should be a curated conversation that guides a customer toward a 
goal, not a generic list of links that pushes them back to the open web.&lt;/p&gt;&lt;figure&gt;&lt;a href="https://files.smashing.media/articles/site-search-paradox-why-big-box-always-wins/4-search-results.jpg"&gt;&lt;img alt="Shows search results with useful options when there are no exact matches. Additional suggestions are provided, including a “Did you mean” feature to help connect users with similar items." height="817" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/site-search-paradox-why-big-box-always-wins/4-search-results.jpg" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;Shows
 search results with useful options when there are no exact matches. 
Additional suggestions are provided, including a “Did you mean” feature 
to help connect users with similar items. (Image source: &lt;a href="https://www.crateandbarrel.com/"&gt;Crate &amp;amp; Barrel&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;div aria-hidden="true" class="c-friskies-box partners partners__lead partners__lead-place partners__external" data-amount="1" data-audience="non-subscriber" data-remove="true"&gt;&lt;/div&gt;&lt;h2 id="the-simple-search-ux-checklist"&gt;The Simple Search UX Checklist&lt;/h2&gt;&lt;p&gt;Here
 is a final checklist for reference when you are building the search 
experience for your users. Work with your product team to ensure you are
 engaging with the right team members.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Kill the dead-end.&lt;/strong&gt;&lt;br /&gt;Never just say “&lt;strong&gt;No results found&lt;/strong&gt;.” If an exact match isn’t there, suggest a similar category, a popular product, or a way to contact support.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Fix “almost” matches.&lt;/strong&gt;&lt;br /&gt;Make
 sure the search can handle plurals (like “plant” vs. “plants”) and 
common typos. Users shouldn’t be punished for a slip of the thumb.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Predict the user’s goal.&lt;/strong&gt;&lt;br /&gt;Use an “auto-suggest” menu to show helpful actions (like “Track my order”) or categories, not just a list of words.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Talk like a human.&lt;/strong&gt;&lt;br /&gt;Look
 at your search logs to see the words people actually use. If they type 
“couch” and you call it “sofa,” create a bridge in the background so 
they find what they need anyway.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Smart filtering.&lt;/strong&gt;&lt;br /&gt;Only
 show filters that matter. If someone searches for “shoes,” show them 
size and color filters, not a generic list that applies to the whole 
site.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Show, don’t just list.&lt;/strong&gt;&lt;br /&gt;Use small 
thumbnails and clear labels in the search results so users can see the 
difference between a product, a blog post, and a help article at a 
glance.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Speed is trust.&lt;/strong&gt;&lt;br /&gt;If the search takes more than a second, use a loading animation. If it’s too slow, people will immediately go back to Google.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Check the “failure” logs.&lt;/strong&gt;&lt;br /&gt;Once
 a month, look at what people searched for that returned zero results. 
This is your “to-do list” for fixing your site’s navigation.&lt;/li&gt;&lt;/ul&gt;&lt;h2 id="conclusion-the-search-bar-is-a-conversation"&gt;Conclusion: The Search Bar Is A Conversation&lt;/h2&gt;&lt;p&gt;The
 search box is the only place on your site where the user tells us 
exactly, in their own words, what they want. When we fail to understand 
those words, when we let the “Big Box” of Google do the work for us, we 
aren’t just losing a page view. We are losing the opportunity to prove 
that we &lt;strong&gt;understand&lt;/strong&gt; our customers.&lt;/p&gt;&lt;blockquote class="pull-quote"&gt;&lt;p&gt;&lt;a aria-label="Share on Twitter" class="pull-quote__link" href="https://twitter.com/share?text=%0aSuccess%20in%20modern%20UX%20isn%e2%80%99t%20about%20having%20the%20most%20content;%20it%e2%80%99s%20about%20having%20the%20most%20findable%20content.%20It%e2%80%99s%20time%20to%20stop%20taxing%20users%20for%20their%20syntax%20and%20start%20designing%20for%20their%20intent.%0a&amp;amp;url=https://smashingmagazine.com%2f2026%2f03%2fsite-search-paradox-why-big-box-always-wins%2f"&gt;Success
 in modern UX isn’t about having the most content; it’s about having the
 most findable content. It’s time to stop taxing users for their syntax 
and start designing for their intent.&lt;/a&gt;&lt;/p&gt;&lt;div class="pull-quote__quotation"&gt;&lt;div class="pull-quote__bg"&gt;&lt;span class="pull-quote__symbol"&gt;“&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;p&gt;By
 moving from literal string matching to semantic understanding, and by 
supporting our search engines with robust, human-centered Information 
Architecture, we can finally close the gap.&lt;/p&gt;</description><link>http://honeyvig.blogspot.com/2026/04/the-site-search-paradox-why-big-box.html</link><author>noreply@blogger.com (H)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-9165069509664255576.post-6938033417554899952</guid><pubDate>Tue, 28 Apr 2026 06:52:00 +0000</pubDate><atom:updated>2026-04-27T23:52:00.118-07:00</atom:updated><title>A Practical Guide To Design Principles</title><description>&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="c-garfield-summary"&gt;&lt;section aria-label="Quick summary" class="article__summary"&gt;by Vitaly.&lt;/section&gt;&lt;/div&gt;&lt;p&gt;We often see design principles as rigid guidelines that dictate design decisions. But actually, they are an incredible tool to &lt;strong&gt;rally the team around a shared purpose&lt;/strong&gt; and document the values and beliefs that an organization embodies.&lt;/p&gt;&lt;p&gt;They
 align teams and inform decision-making. They also keep us afloat amidst
 all the hype, big assumptions, desire for faster delivery, and AI 
workslop. But how do we choose the right ones, and how do we get 
started? Let’s find out.&lt;/p&gt;&lt;h2 id="real-world-design-principles"&gt;Real-World Design Principles&lt;/h2&gt;&lt;p&gt;In times when we can generate any passable design and code within minutes, we need to decide better &lt;strong&gt;what’s worth designing and building&lt;/strong&gt; — and what values we want our products to embody.&lt;/p&gt;&lt;p&gt;It’s
 similar to voice and tone. You might not design it intentionally, but 
then end users will define it for you. And so, without principles, many 
company initiatives are &lt;strong&gt;random, sporadic, ad-hoc&lt;/strong&gt; — and feel vague, inconsistent, or simply dull to the outside world.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Design principles&lt;/strong&gt; are guidelines and design considerations that &lt;a href="https://ixdf.org/literature/topics/design-principles"&gt;designers apply with discretion&lt;/a&gt; — by default, without debating or discussing what has already been agreed upon.&lt;/p&gt;&lt;p&gt;One fantastic resource that I keep coming back to after all these years is Ben Brignell’s &lt;a href="https://principles.design"&gt;Principles.design&lt;/a&gt;. It has &lt;strong&gt;230 pointers for design principles and methods&lt;/strong&gt;, searchable and tagged, covering everything from language and infrastructure to hardware and organizations.&lt;/p&gt;&lt;h2 id="10-principles-of-good-design"&gt;10 Principles Of Good Design&amp;nbsp;&lt;/h2&gt;&lt;p&gt;There is no shortage of principles out there. But the good ones are more than just being &lt;em&gt;visionary&lt;/em&gt; — they &lt;strong&gt;have a point of view&lt;/strong&gt;, and they explain what we &lt;em&gt;don’t do&lt;/em&gt; as much as what we do. They also explain what &lt;strong&gt;we stand for&lt;/strong&gt; in the world — beyond profits, stock prices, and all the hype and noise around us.&lt;/p&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://www.vitsoe.com/gb/about/good-design#good-design-is-innovative"&gt;&lt;img alt="10 legendary principles for good design" height="559" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/stop-endless-debates-design-principles/1-principles-good-design.jpg" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;10 legendary principles for good design, by &lt;a href="https://www.vitsoe.com/gb/about/good-design#good-design-is-innovative"&gt;Dieter Rams&lt;/a&gt;. Still relevant, after all these years.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;Many years ago, I encountered &lt;a href="https://www.vitsoe.com/gb/about/good-design#good-design-is-innovative"&gt;Dieter Rams’ 10 principles of good design&lt;/a&gt; (see above), a very &lt;strong&gt;humble, practical and tangible&lt;/strong&gt; overview of principles that were informing, shaping, and guarding his design work at Braun.&lt;/p&gt;&lt;p&gt;There are &lt;strong&gt;no visionary claims&lt;/strong&gt;,
 and no big bold statements: just a clear overview of what we do, and 
where our ambition and care lie for the products we are designing. It’s 
honest, sincere, and in many ways beautifully &lt;strong&gt;humane&lt;/strong&gt;.&lt;/p&gt;&lt;h3 id="examples-of-design-principles"&gt;Examples Of Design Principles&amp;nbsp;&lt;/h3&gt;&lt;p&gt;There are plenty of &lt;strong&gt;wonderful examples&lt;/strong&gt; that I keep close:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://www.anthropic.com/constitution"&gt;Anthropic’s Constitution&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://principles.design/examples/principles-of-product-design"&gt;Principles of Product Design&lt;/a&gt;, by Joshua Porter&lt;/li&gt;&lt;li&gt;&lt;a href="https://principles.design/examples/20-guiding-principles-for-experience-design"&gt;Guiding Principles for Experience Design&lt;/a&gt;, by Whitney Hess, PCC&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/Heydon/principles-of-web-accessibility"&gt;Principles of Web Accessibility&lt;/a&gt;, by Heydon Pickering&lt;/li&gt;&lt;li&gt;&lt;a href="https://humanebydesign.com"&gt;Humane by Design&lt;/a&gt;, by Jon Yablonski&lt;/li&gt;&lt;li&gt;&lt;a href="https://principles.design/examples/designing-for-voice-interfaces"&gt;Designing Voice UX Principles&lt;/a&gt;, by Brian Colcord&lt;/li&gt;&lt;li&gt;&lt;a href="https://linear.app/developers/aig"&gt;Agentic Design Principles&lt;/a&gt;, by Linear&lt;/li&gt;&lt;li&gt;&lt;a href="https://www.intercom.com/blog/principles-bot-design/"&gt;AI Chatbot Design Principles&lt;/a&gt;, by Emmet Connolly&lt;/li&gt;&lt;li&gt;&lt;a href="https://voiceprinciples.com"&gt;Voice UX Principles&lt;/a&gt;, by Ben Sauer&lt;/li&gt;&lt;/ul&gt;&lt;h3 id="design-principles-in-design-systems"&gt;Design Principles In Design Systems&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://guides.18f.org/"&gt;18F&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://styleguide.audi.com/document/2440#/-/experience-principles"&gt;Audi&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://www.ibm.com/design/language/philosophy/principles/"&gt;Carbon (IBM)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://acorn.firefox.com/latest/get-started/firefox-design-principles-5ezPvNdo"&gt;Firefox&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://www.gov.uk/guidance/government-design-principles"&gt;Gov.uk&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://contentdesign.intuit.com/style-and-usage/our-principles/"&gt;Intuit&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://service-manual.nhs.uk/design-system/design-principles"&gt;NHS&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://nordhealth.design/principles/"&gt;Nordhealth&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://base.uber.com/6d2425e9f/p/434f39-principles"&gt;Uber&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 id="how-to-establish-design-principles"&gt;How To Establish Design Principles&lt;/h2&gt;&lt;p&gt;Design principles can be personal, but usually they are committed to and shaped by the &lt;strong&gt;entire product team&lt;/strong&gt;. Design principles &lt;strong&gt;aren’t just for designers&lt;/strong&gt;. User’s experience is &lt;em&gt;everything&lt;/em&gt; from performance to support to customer service, and ideally, participants would cover these areas as well.&lt;/p&gt;&lt;p&gt;In
 practice, though, establishing principles might feel incredibly 
challenging. They are abstract and fluffy and often ambiguous, and often
 very difficult to agree upon.&lt;/p&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://www.figma.com/community/file/1051212964426062558"&gt;&lt;img alt="Workshop kit for a design principles workshop" height="461" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/stop-endless-debates-design-principles/2-design-principles-workshop.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;&lt;a href="https://www.figma.com/community/file/1051212964426062558"&gt;One of many workshop kits&lt;/a&gt; for a design principles workshop.&amp;nbsp;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;You can get started with a &lt;strong&gt;simple 8-step workshop&lt;/strong&gt; (inspired by &lt;a href="https://medium.com/@marcintreder/design-system-sprint-4-design-principles-8efb22d8a208"&gt;Marcin Treder&lt;/a&gt;, &lt;a href="https://medium.com/design-bootcamp/design-principles-workshop-a-template-15c7c90458f2"&gt;Maria Meireles&lt;/a&gt; and &lt;a href="https://www.better.care/blog-en/establishing-design-principles-for-a-design-system-and-what-it-taught-us/"&gt;Better&lt;/a&gt;):&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;Pre-session Research&lt;/strong&gt;&lt;br /&gt;Study how users speak about the products, what they appreciate, and the words they use.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Get Into Principles Mode&lt;/strong&gt;&lt;br /&gt;Invite 6–8 participants, ask them to choose their favorite object, and describe it in 3 words.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Product Analogies&lt;/strong&gt;&lt;br /&gt;Compare product to tangible items (e.g., ‘A Porsche 911’ or ‘a Braun audio system’).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Extract Attributes&lt;/strong&gt;&lt;br /&gt;Individually, in silence, everyone writes 3–5 initial principles, which are then grouped by theme for review.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Link Attributes To Research&lt;/strong&gt;&lt;br /&gt;Link attributes to actual user pain points or desires, to make sure they are grounded in reality.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Value Statements&lt;/strong&gt;&lt;br /&gt;We write &lt;em&gt;‘We want X because of Y’&lt;/em&gt; sentences that express the rationale behind our thinking.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Move to Principles&lt;/strong&gt;&lt;br /&gt;Remove analogies to create enduring rules that will guide our design process.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Reality Check&lt;/strong&gt;&lt;br /&gt;Search for both positive and negative examples in our products to see where principles are being met or ignored.&lt;/li&gt;&lt;/ol&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://www.better.care/blog-en/establishing-design-principles-for-a-design-system-and-what-it-taught-us/"&gt;&lt;img alt="Variants of sentences for establishing design principles" height="492" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/stop-endless-debates-design-principles/3-design-principles.jpg" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;Voting for the most relevant sentences in keyword groups. From &lt;a href="https://www.better.care/blog-en/establishing-design-principles-for-a-design-system-and-what-it-taught-us/"&gt;Better&lt;/a&gt;. (&lt;a href="https://files.smashing.media/articles/stop-endless-debates-design-principles/3-design-principles.jpg"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;h3 id="useful-starter-kits-for-principles-workshops"&gt;Useful Starter Kits For Principles Workshops&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/04/practical-guide-design-principles/#useful-starter-kits-for-principles-workshops"&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://medium.com/design-bootcamp/design-principles-workshop-a-template-15c7c90458f2"&gt;Design Principles Workshop (Figma Template)&lt;/a&gt;, by Maria Meireles&lt;/li&gt;&lt;li&gt;&lt;a href="https://www.figma.com/community/file/1051212964426062558"&gt;Design Principles Workshop (FigJam Template)&lt;/a&gt;, by Richard Picot&lt;/li&gt;&lt;li&gt;&lt;a href="https://miro.com/templates/design-principles-workshop/"&gt;How to Create Design Principles (Miro Workshop Template)&lt;/a&gt;, by NanoGiants&lt;/li&gt;&lt;/ul&gt;&lt;h2 id="wrapping-up"&gt;Wrapping Up&amp;nbsp;&lt;/h2&gt;&lt;p&gt;Creating principles is only a small portion of the work; most work is about &lt;strong&gt;effectively sharing and embedding them&lt;/strong&gt;. It’s difficult to get anywhere without finding ways to &lt;strong&gt;make design principles a default&lt;/strong&gt; — by revisiting settings, templates, naming conventions, and output.&lt;/p&gt;&lt;p&gt;Principles help &lt;strong&gt;avoid endless discussions&lt;/strong&gt;
 that often stem from personal preferences or taste. But design should 
not be a matter of taste; it must be guided by our goals and values. 
Design principles can help with just that.&lt;/p&gt;&lt;h2 id="useful-resources"&gt;Useful Resources&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://principles.design"&gt;Design Principles Collection&lt;/a&gt;, by Ben Brignell&lt;/li&gt;&lt;li&gt;“&lt;a href="https://medium.com/@marcintreder/design-system-sprint-4-design-principles-8efb22d8a208"&gt;How To Establish Design Principles&lt;/a&gt;”, by Marcin Treder&lt;/li&gt;&lt;li&gt;“&lt;a href="https://www.better.care/blog-en/establishing-design-principles-for-a-design-system-and-what-it-taught-us/"&gt;Establishing Design Principles for a Design System and What It Taught Us&lt;/a&gt;”, by Better Design Team&lt;/li&gt;&lt;li&gt;&lt;a href="https://principles.adactio.com"&gt;Design Principles&lt;/a&gt;, by Jeremy Keith&lt;/li&gt;&lt;li&gt;&lt;a href="https://www.designprinciplesftw.com"&gt;Design Principles Collection&lt;/a&gt;, by Gabriel Svennerberg&lt;/li&gt;&lt;li&gt;&lt;a href="https://medium.com/design-bootcamp/design-principles-workshop-a-template-15c7c90458f2"&gt;Design Principles Workshop (Figma Template)&lt;/a&gt;, by Maria Meireles&lt;/li&gt;&lt;li&gt;&lt;a href="https://www.figma.com/community/file/1051212964426062558"&gt;Design Principles Workshop (FigJam Template)&lt;/a&gt;, by Richard Picot&lt;/li&gt;&lt;li&gt;&lt;a href="https://miro.com/templates/design-principles-workshop/"&gt;How to Create Design Principles (Miro Workshop Template)&lt;/a&gt;, by NanoGiants&lt;/li&gt;&lt;li&gt;&lt;a href="https://designsystems.surf/components/modal"&gt;Modals in Design Systems&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;</description><link>http://honeyvig.blogspot.com/2026/04/a-practical-guide-to-design-principles.html</link><author>noreply@blogger.com (H)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-9165069509664255576.post-7433714191173803800</guid><pubDate>Mon, 27 Apr 2026 08:53:00 +0000</pubDate><atom:updated>2026-04-27T01:53:02.232-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Feature Engineering Feature</category><title>Why Senior Engineers Go Quiet — The Hidden 3-Week Warning Before Failure</title><description>&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p class="ember-view reader-text-block__paragraph" id="ember62"&gt;
      &lt;em&gt;Delivery intelligence for technology leaders&lt;/em&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;· &amp;nbsp; Issue #40 &amp;nbsp; · &amp;nbsp; Every Wednesday
    &lt;/p&gt;

  






            
        
    &lt;h2 class="ember-view reader-text-block__heading-2" id="ember63"&gt;
      Not 3 months. Not 3 weeks of runway. 3 weeks until something breaks.
    &lt;/h2&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember64"&gt;
      &lt;em&gt;Disclaimer: Details in this issue have been changed to protect client confidentiality. The situation and the lesson are real&lt;/em&gt;
    &lt;/p&gt;

  










            
  &lt;hr class="reader-divider-block__horizontal-rule" /&gt;



            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember65"&gt;
      &lt;strong&gt;She had been the most engaged person in every stand-up for 7 months.&lt;/strong&gt;
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember66"&gt;
      The lead engineer on our most complex workstream. Sharp, direct, 
the kind of person who would call out a bad architectural decision in 
front of the client without hesitation. She had identified three 
significant technical risks in the first quarter, all of which were 
caught before they reached the backlog. The team trusted her completely.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember67"&gt;
      In week 29, I noticed she had not challenged anything in stand-up 
for 6 days. She was answering her 3 questions. She was present. She was 
doing her work. She had just stopped.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember68"&gt;
      &lt;em&gt;"Yesterday I finished the integration layer. Today I'm continuing the same. No blockers."&lt;/em&gt;
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember69"&gt;
      Eleven days later, the integration layer failed under load. It was
 not a simple bug. It was a structural decision that had been made in 
week 26 - one she had known was wrong, had decided not to raise, and had
 spent the following three weeks building around.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember70"&gt;
      When I asked her why she had not flagged it, her answer was more honest than I had expected:&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;strong&gt;&lt;em&gt;"I
 raised two things in month 5 and both times I felt like I was being 
managed rather than heard. I decided it wasn't worth the energy."&lt;/em&gt;&lt;/strong&gt;
    &lt;/p&gt;

  










            
  &lt;hr class="reader-divider-block__horizontal-rule" /&gt;



            
        &lt;pre class="reader-text-block__code-block"&gt;&lt;code&gt;Today's menu:

&#128680;  The problem: The specific silence pattern that precedes every major technical failure I have seen in 14 years and why it is always the most capable person who goes quiet first

&#128184;  What it costs: Why the silence of senior engineers is the most accurate leading indicator of delivery risk available and why it never appears on a RAID log

✅  The fix: The 3-week intervention that catches the pattern before it becomes a crisis&lt;/code&gt;&lt;/pre&gt;
  










            
  &lt;hr class="reader-divider-block__horizontal-rule" /&gt;



            
        
    &lt;h3 class="ember-view reader-text-block__heading-3" id="ember71"&gt;
      ⚠️&amp;nbsp; The silence pattern — what it is and why the best person goes first
    &lt;/h3&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember72"&gt;
      Senior engineers go quiet in stand-ups for a specific, 
identifiable reason that is almost never the one delivery leaders 
assume. It is not burnout — burnout produces agitation before silence. 
It is not disengagement — disengagement produces lower quality work, not
 lower verbal frequency. And it is almost never satisfaction.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember73"&gt;
      The most common cause of senior-engineer silence in a 
well-functioning team is a specific, rational cost-benefit calculation: 
the engineer has assessed that the cost of raising a concern — the 
social friction, the pushback, the feeling of being managed — is greater
 than the benefit of having the concern heard. And they have made this 
calculation based on evidence from the programme.
    &lt;/p&gt;

  






            
        
    &lt;blockquote class="ember-view reader-text-block__blockquote" id="ember74"&gt;
      &lt;em&gt;Senior engineers do not go quiet because they have nothing to 
say. They go quiet because they have learned that saying it is not worth
 it.&lt;/em&gt;
    &lt;/blockquote&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember75"&gt;
      The reason the best engineer goes first is exactly their 
seniority. A junior developer raises concerns because they are still 
learning the social norms of the team. A senior engineer has already 
made the social calculation with much more precision — and has enough 
other things to focus on that withdrawing from verbal risk-raising is a 
rational conservation of energy.
    &lt;/p&gt;

  







              
    &lt;div class="reader-image-block reader-image-block--full-width"&gt;
      &lt;figure class="reader-image-block__figure"&gt;
          
    &lt;div class="ivm-image-view-model    reader-image-block__img-container"&gt;
        
    &lt;div class="ivm-view-attr__img-wrapper
        
        "&gt;

          &lt;img alt="Article content" class="ivm-view-attr__img--centered  reader-image-block__img evi-image lazy-image ember-view" id="ember76" src="https://media.licdn.com/dms/image/v2/D4D12AQFJgP8BKfUhDw/article-inline_image-shrink_1500_2232/B4DZ2NPq0XIoAc-/0/1776191189007?e=1778716800&amp;amp;v=beta&amp;amp;t=C_UYyJZ2ldBE-8vTQ2lKZPjpt2h5QhBWGJGmbPt1-yg" /&gt;
    &lt;/div&gt;
  
          &lt;/div&gt;
  

          &lt;figcaption class="reader-image-block__figure-image-caption display-block full-width text-body-small-open t-sans text-align-center t-black--light"&gt;
            
          &lt;/figcaption&gt;
      &lt;/figure&gt;
    &lt;/div&gt;
  









            
  &lt;hr class="reader-divider-block__horizontal-rule" /&gt;



            
        
    &lt;h3 class="ember-view reader-text-block__heading-3" id="ember77"&gt;
      &#129300;&amp;nbsp; Quiz
    &lt;/h3&gt;

  






            
        &lt;pre class="reader-text-block__code-block"&gt;&lt;code&gt;You lead a 12-person engineering team. Your most senior developer historically engaged, opinionated, and reliable has given a variation of "all good, no blockers" in stand-up for 8 consecutive days. Delivery metrics are normal. What is the right first action?

A)  Nothing — consistent delivery metrics are the signal that matters, not verbal frequency

B)  Ask them directly in the stand-up: "Are you sure there are no blockers? You've been very quiet this week."

C)  Have a private 15-minute conversation outside the stand-up: "I've noticed you have been less vocal recently, is there anything you're sitting on that you haven't raised?"

D)  Send a team-wide message encouraging everyone to raise concerns more actively

&#128073;  Answer at the end of this issue&lt;/code&gt;&lt;/pre&gt;
  










            
  &lt;hr class="reader-divider-block__horizontal-rule" /&gt;



            
        
    &lt;h3 class="ember-view reader-text-block__heading-3" id="ember78"&gt;
      &#128161;&amp;nbsp; The fix
    &lt;/h3&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember79"&gt;
      Three interventions timed specifically to the 3-week window before the silence becomes a structural problem.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember80"&gt;
      &lt;strong&gt;✅&amp;nbsp; Fix 1: Week 1 — The private, direct conversation&lt;/strong&gt;
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember81"&gt;
      Within 5 days of noticing the silence, a 15-minute private 
conversation. Not a performance conversation. Not a welfare check. A 
specific, respectful inquiry:
    &lt;/p&gt;

  






            
        
    &lt;blockquote class="ember-view reader-text-block__blockquote" id="ember82"&gt;
      &lt;em&gt;"I've noticed you've been less vocal in stand-ups recently. I 
want to make sure I'm not missing something important. Is there anything
 you are sitting on technically or otherwise that you haven't raised?"&lt;/em&gt;
    &lt;/blockquote&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember83"&gt;
      The silence after this question is important. Do not fill it. The 
engineer is doing a rapid cost-benefit recalculation. Is this person 
going to hear what I say or manage it? Your job in the first 90 seconds 
after they speak is to demonstrate, specifically and behaviourally, that
 you are doing the former.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember84"&gt;
      If they say "nothing, all fine": thank them and leave the door 
open. Watch for a second week of silence. If that occurs, the 
calculation has been made and you need the next intervention.
    &lt;/p&gt;

  







              
    &lt;div class="reader-image-block reader-image-block--full-width"&gt;
      &lt;figure class="reader-image-block__figure"&gt;
          
    &lt;div class="ivm-image-view-model    reader-image-block__img-container"&gt;
        
    &lt;div class="ivm-view-attr__img-wrapper
        
        "&gt;

          &lt;img alt="Article content" class="ivm-view-attr__img--centered  reader-image-block__img evi-image lazy-image ember-view" id="ember85" src="https://media.licdn.com/dms/image/v2/D4D12AQH07i6UrxSi4g/article-inline_image-shrink_1500_2232/B4DZ2NQeiLJ0Ac-/0/1776191400643?e=1778716800&amp;amp;v=beta&amp;amp;t=Uqsut-Zb6No338Xl8Moe_j4pDCWGIJTKy7NzMVNQJkA" /&gt;
    &lt;/div&gt;
  
          &lt;/div&gt;
  

          &lt;figcaption class="reader-image-block__figure-image-caption display-block full-width text-body-small-open t-sans text-align-center t-black--light"&gt;
            
          &lt;/figcaption&gt;
      &lt;/figure&gt;
    &lt;/div&gt;
  





            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember86"&gt;
      &lt;strong&gt;✅&amp;nbsp; Fix 2: Week 2 — The concern-cost audit&lt;/strong&gt;
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember87"&gt;
      If the private conversation has not produced the information, the 
issue is structural: the cost of raising concerns in this team is too 
high. A 45-minute session with the senior engineers only, no junior team
 members, with one question:
    &lt;/p&gt;

  






            
        
    &lt;blockquote class="ember-view reader-text-block__blockquote" id="ember88"&gt;
      &lt;em&gt;"Think of the last time you identified a concern on this 
programme and decided not to raise it. What made you decide not to raise
 it?"&lt;/em&gt;
    &lt;/blockquote&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember89"&gt;
      Write every answer on a whiteboard. Do not defend against any of 
them. Do not explain or contextualise. Just write them down and read 
them back. The act of making the concern-cost visible, in a room, 
without defensiveness, is often enough to change the dynamic because it 
signals that this is now a problem you are taking seriously rather than 
managing.
    &lt;/p&gt;

  







              
    &lt;div class="reader-image-block reader-image-block--full-width"&gt;
      &lt;figure class="reader-image-block__figure"&gt;
          
    &lt;div class="ivm-image-view-model    reader-image-block__img-container"&gt;
        
    &lt;div class="ivm-view-attr__img-wrapper
        
        "&gt;

          &lt;img alt="Article content" class="ivm-view-attr__img--centered  reader-image-block__img evi-image lazy-image ember-view" id="ember90" src="https://media.licdn.com/dms/image/v2/D4D12AQFEm7oCExGt6A/article-inline_image-shrink_1000_1488/B4DZ2NQx9.J0AQ-/0/1776191480675?e=1778716800&amp;amp;v=beta&amp;amp;t=DDXn1E__0nYmpjqSjXPy5n8yTvxqHvbZARz0W2NiAyo" /&gt;
    &lt;/div&gt;
  
          &lt;/div&gt;
  

          &lt;figcaption class="reader-image-block__figure-image-caption display-block full-width text-body-small-open t-sans text-align-center t-black--light"&gt;
            
          &lt;/figcaption&gt;
      &lt;/figure&gt;
    &lt;/div&gt;
  





            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember91"&gt;
      &lt;strong&gt;✅&amp;nbsp; Fix 3: Week 3 — The structural fix builds concern-raising into the process, not the person&lt;/strong&gt;
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember92"&gt;
      If the silence persists into week 3, the issue is not about the 
individual engineer. It is about the environment. Three structural 
changes that reduce the cost of raising concerns at the team level:
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember93"&gt;
            &lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;The end-of-day risk log.&lt;/strong&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;A
 standing Slack channel or equivalent where the only acceptable input is
 "I noticed X today and I am not sure whether it is a risk." No 
resolution required. No follow-up demanded. Just observation. The 
programme lead acknowledges every entry within 24 hours.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The pre-commitment check.&lt;/strong&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;Before
 any architectural or technical decision is finalised, one question is 
asked of the most senior person who disagreed with it: "What would need 
to happen for you to be proven right?" This gives dissent a legitimate 
structural role instead of requiring it to be raised as a confrontation.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The monthly technical retrospective.&lt;/strong&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;Separate
 from the delivery retrospective. Focused entirely on technical 
decisions: what are we building that we are not comfortable with? This 
is where the concerns that are too technical to raise in a delivery 
forum find a legitimate place.&lt;/li&gt;&lt;/ul&gt;

    &lt;p&gt;&lt;/p&gt;

  







              
    &lt;div class="reader-image-block reader-image-block--full-width"&gt;
      &lt;figure class="reader-image-block__figure"&gt;
          
    &lt;div class="ivm-image-view-model    reader-image-block__img-container"&gt;
        
    &lt;div class="ivm-view-attr__img-wrapper
        
        "&gt;

          &lt;img alt="Article content" class="ivm-view-attr__img--centered  reader-image-block__img evi-image lazy-image ember-view" id="ember94" src="https://media.licdn.com/dms/image/v2/D4D12AQG9SNJ78kHNMg/article-inline_image-shrink_1500_2232/B4DZ2NRDVEG0AU-/0/1776191551367?e=1778716800&amp;amp;v=beta&amp;amp;t=mwbh-yxgC90C7TutpNXImwmWj7dN-gc5ydgLMHjDKwg" /&gt;
    &lt;/div&gt;
  
          &lt;/div&gt;
  

          &lt;figcaption class="reader-image-block__figure-image-caption display-block full-width text-body-small-open t-sans text-align-center t-black--light"&gt;
            
          &lt;/figcaption&gt;
      &lt;/figure&gt;
    &lt;/div&gt;
  









            
  &lt;hr class="reader-divider-block__horizontal-rule" /&gt;



            
        
    &lt;h3 class="ember-view reader-text-block__heading-3" id="ember95"&gt;
      &#127919;&amp;nbsp; What to do this week
    &lt;/h3&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember96"&gt;
      This week, track one metric you have probably never tracked before:
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember97"&gt;
            &lt;/p&gt;&lt;ul&gt;&lt;li&gt;For the three most senior engineers on your team: 
how many substantive observations (concerns, challenges, technical 
flags) have they made in stand-ups and ceremonies in the last 10 working
 days?&lt;/li&gt;&lt;li&gt;Not "did they attend." Not "are they performing." How many times did they say something that was not a status update?&lt;/li&gt;&lt;/ul&gt;

    &lt;p&gt;&lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember98"&gt;
      If the answer is fewer than two per person per week: you may have a silence pattern forming.&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;strong&gt;You now have 3 weeks before it becomes a structural problem.&lt;/strong&gt;
    &lt;/p&gt;

  










            
  &lt;hr class="reader-divider-block__horizontal-rule" /&gt;



            
        &lt;pre class="reader-text-block__code-block"&gt;&lt;code&gt;Want the concern-cost audit questions — the exact 45-minute format?

Reply "silence" to this email and I'll send it directly to you.&lt;/code&gt;&lt;/pre&gt;
  










            
  &lt;hr class="reader-divider-block__horizontal-rule" /&gt;



            
        
    &lt;h3 class="ember-view reader-text-block__heading-3" id="ember99"&gt;
      &#127760;&amp;nbsp; Around the web this week
    &lt;/h3&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember100"&gt;
      &lt;strong&gt;⚡&amp;nbsp; 1 tool:&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;/strong&gt;TeamRetro
 — asynchronous retrospective tool with anonymous input. The specific 
use case: a standing "what am I not saying" prompt that team members can
 contribute to before the synchronous session. The anonymity removes the
 social cost before the concern reaches the room.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember101"&gt;
      &lt;strong&gt;&#128202;&amp;nbsp; 1 number:&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;/strong&gt;Google's
 Project Aristotle research found that psychological safety, the belief 
that one will not be punished for raising concerns, is the single 
strongest predictor of team effectiveness across the 180 teams studied. 
It ranked above all technical, organisational, and individual competence
 factors. The silence pattern is what happens when psychological safety 
has already failed.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember102"&gt;
      &lt;strong&gt;&#128172;&amp;nbsp; 1 quote:&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;/strong&gt;&lt;em&gt;"What
 got you here won't get you there." - Marshall Goldsmith. For delivery 
leaders, what got you here: confidence, decisiveness, pattern-matching 
from experience, is precisely what creates the silence in your best 
people. Success and the conditions for future success are not the same 
thing.&lt;/em&gt;
    &lt;/p&gt;

  










            
  &lt;hr class="reader-divider-block__horizontal-rule" /&gt;



            
        
    &lt;h3 class="ember-view reader-text-block__heading-3" id="ember103"&gt;
      &#128073;&amp;nbsp; Quiz answer
    &lt;/h3&gt;

  






            
        
    &lt;blockquote class="ember-view reader-text-block__blockquote" id="ember104"&gt;
      &lt;strong&gt;C — private, direct, and non-accusatory.&lt;/strong&gt;
    &lt;/blockquote&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember105"&gt;
      Option A is the most common response and the most dangerous, it 
treats delivery metrics as the only signal that matters, which is the 
assumption that allows this pattern to reach crisis. Option B creates a 
public moment that compounds the social cost already causing the 
silence. Option D is too diffuse to address the specific pattern and may
 actually increase the cost of raising concerns by making it feel 
scrutinised.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember106"&gt;
      Option C works because it is private, it is observational rather 
than accusatory ("I've noticed" not "why aren't you"), and it 
specifically names the concern about unraised issues. It gives the 
engineer a low-cost way to surface what they are sitting on without 
requiring them to do it in front of the team. The phrase "is there 
anything you're sitting on" is important — it names the specific pattern
 you are looking for.
    &lt;/p&gt;

  










            
  &lt;hr class="reader-divider-block__horizontal-rule" /&gt;



            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember107"&gt;
      The lead engineer I described in the opening story is, as far as I
 know, thriving. She left the programme at the end of that engagement — 
not because of the incident, but because the engagement ended.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember108"&gt;
      What she taught me by going quiet, by deciding three weeks before 
the failure that raising concerns was not worth the energy, is something
 I now treat as the most important signal in any programme I lead. Not 
the RAG status. Not the velocity chart. The voice of the most capable 
person in the room.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember109"&gt;
      &lt;strong&gt;When that voice goes quiet, everything else is noise. The 3-week clock is already running.&lt;/strong&gt;
    &lt;/p&gt;

  






            
        
    &lt;blockquote class="ember-view reader-text-block__blockquote" id="ember110"&gt;
      Think of the most technically capable person on your current team.
 When did they last challenge something, a decision, an assumption, a 
plan in a group setting? If you cannot remember, the clock may already 
be running.
    &lt;/blockquote&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember111"&gt;
      &lt;em&gt;Hit reply. I read everything.&lt;/em&gt;
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember112"&gt;
      Until next Wednesday,
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember113"&gt;
      &lt;strong&gt;Aman&lt;/strong&gt;
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember114"&gt;
      &lt;a class="xwxVfcRwnBUeGipgoiZPeKPJMrvzgAVqE " data-test-app-aware-link="" href="http://www.amansingh.pro" tabindex="0" target="_self"&gt;&lt;em&gt;www.amansingh.pro&lt;/em&gt;&lt;/a&gt;
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember115"&gt;
      
        &lt;br /&gt;
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember116"&gt;
      &lt;em&gt;If this issue is named something you have been watching but could not describe, forward it to one person who needs to read it.&lt;/em&gt;
    &lt;/p&gt;</description><link>http://honeyvig.blogspot.com/2026/04/why-senior-engineers-go-quiet-hidden-3.html</link><author>noreply@blogger.com (H)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-9165069509664255576.post-233338858945345680</guid><pubDate>Mon, 27 Apr 2026 06:50:00 +0000</pubDate><atom:updated>2026-04-26T23:50:42.834-07:00</atom:updated><title>How To Improve UX In Legacy Systems</title><description>&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="c-garfield-summary"&gt;&lt;section aria-label="Quick summary" class="article__summary"&gt;Practical guidelines for driving UX impact in organizations with legacy systems and broken processes. Brought to you by &lt;a href="https://measure-ux.com/"&gt;Measuring UX Impact&lt;/a&gt;, &lt;strong&gt;friendly video course on UX&lt;/strong&gt; and design patterns by Vitaly.&lt;/section&gt;&lt;/div&gt;&lt;p&gt;Imagine that you need to improve the &lt;strong&gt;UX of a legacy system&lt;/strong&gt;.
 A system that has been silently working in the background for almost a 
decade. It’s slow, half-broken, unreliable, and severely outdated — a 
sort of “black box” that everyone relies upon, but nobody really knows 
what’s happening under the hood.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Where would you even start?&lt;/strong&gt;
 Legacy stories are often daunting, adventurous, and utterly confusing. 
They represent a mixture of fast-paced decisions, quick fixes, and 
accumulating UX debt.&lt;/p&gt;&lt;p&gt;There is no one-fits-all solution to tackle them, but there are ways to make progress, albeit slowly, while respecting the &lt;strong&gt;needs and concerns&lt;/strong&gt; of users and stakeholders. Now, let’s see how we can do just that.&lt;/p&gt;&lt;h2 id="the-actual-challenges-of-legacy-ux"&gt;The Actual Challenges Of Legacy UX&lt;/h2&gt;&lt;p&gt;It might feel that legacy products are waiting to be deprecated at any moment. But in reality, they are often &lt;strong&gt;critical for daily operations&lt;/strong&gt;.
 Many legacy systems are heavily customized for the needs of the 
organization, often built externally by a supplier and often without 
rigorous usability testing.&lt;/p&gt;&lt;p&gt;It’s common for enterprises to spend &lt;strong&gt;40–60% of their time&lt;/strong&gt; managing, maintaining, and fine-tuning legacy systems. They are essential, critical — but also very expensive to keep alive.&lt;/p&gt;&lt;figure&gt;&lt;a href="https://files.smashing.media/articles/how-improve-ux-legacy-systems/1-cash-register.jpg"&gt;&lt;img alt="A detailed electronic medical record (EMR) screen for an ophthalmology patient, displaying their visit summary including chief complaint, past medical history, medications, and optical test results." height="500" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-improve-ux-legacy-systems/1-cash-register.jpg" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;Cash
 registers are frequently designed once and rarely touched again. 
Replacing them across 1000s of stores is remarkably expensive.&amp;nbsp;&lt;/figcaption&gt;&lt;/figure&gt;&lt;h3 id="1-legacy-must-co-exist-with-products-built-around-them"&gt;1. Legacy Must Co-Exist With Products Built Around Them&lt;/h3&gt;&lt;p&gt;Running in a &lt;strong&gt;broken, decade-old ecosystem&lt;/strong&gt;,
 legacy still works, yet nobody knows exactly how and why it still does.
 People who have set it up originally probably have left the company 
years ago, leaving a lot of unknowns and poorly documented work behind.&lt;/p&gt;&lt;p&gt;With them come &lt;strong&gt;fragmented and inconsistent design choices&lt;/strong&gt;, stuck in old versions of old design tools that have long been discontinued.&lt;/p&gt;&lt;figure&gt;&lt;a href="https://files.smashing.media/articles/how-improve-ux-legacy-systems/2-legacy-system-healthcare.jpg"&gt;&lt;img alt="A detailed electronic medical record (EMR) screen for an ophthalmology patient, displaying their visit summary including chief complaint, past medical history, medications, and optical test results." src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-improve-ux-legacy-systems/2-legacy-system-healthcare.jpg" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;One of many: a legacy system used by EMR systems in healthcare.&amp;nbsp;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;Still, legacy systems must neatly &lt;strong&gt;co-exist within modern digital products&lt;/strong&gt;
 built around them. In many ways, the end result resembles a 
Frankenstein — many bits and pieces glued together, often a mixture of 
modern UIs and painfully slow and barely usable fragments here and there
 — especially when it comes to validation, error messages, or processing
 data.&lt;/p&gt;&lt;h3 id="2-legacy-systems-make-or-break-ux"&gt;2. Legacy Systems Make or Break UX&lt;/h3&gt;&lt;p&gt;Once you sprinkle a little bit of quick bugfixing, unresolved business logic issues, and unresponsive layouts, you have a &lt;strong&gt;truly frustrating experience&lt;/strong&gt;, despite the enormous effort put into the rest of the application.&lt;/p&gt;&lt;p&gt;If one single step in a complex user flow feels &lt;strong&gt;utterly broken and confusing&lt;/strong&gt;,
 then the entire product appears to be broken as well, despite the 
incredible efforts the design teams have put together in the rest of the
 product.&lt;/p&gt;&lt;p&gt;Well, eventually, you’ll have to tackle legacy. And that’s where we need to consider available options for your &lt;strong&gt;UX roadmap&lt;/strong&gt;.&lt;/p&gt;&lt;h2 id="ux-roadmap-for-tackling-legacy-projects"&gt;UX Roadmap For Tackling Legacy Projects&amp;nbsp;&lt;/h2&gt;&lt;h3 id="don-t-dismiss-legacy-build-on-existing-knowledge"&gt;Don’t Dismiss Legacy: Build on Existing Knowledge&lt;/h3&gt;&lt;p&gt;Because
 legacy systems are often big unknowns that cause a lot of frustration 
to everyone, from stakeholders to designers to engineers to users. The 
initial thought might be to remove it entirely and &lt;strong&gt;redesign it from scratch&lt;/strong&gt;, but in practice, that’s not always feasible. Big-bang-redesign is a &lt;strong&gt;remarkably expensive&lt;/strong&gt; and very time-consuming endeavor.&lt;/p&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://files.smashing.media/articles/how-improve-ux-legacy-systems/3-questions-ask-legacy-system.png"&gt;&lt;img alt="An overview of questions to ask key stakeholders to understand the legacy system, its key features, workflows, and priorities." height="467" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-improve-ux-legacy-systems/3-questions-ask-legacy-system.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;First things first: map legacy features, workflows, and priorities as a part of discovery.&amp;nbsp;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;Legacy systems &lt;strong&gt;hold valuable knowledge&lt;/strong&gt;
 about the business practice, and they do work — and a new system must 
perfectly match years of knowledge and customization done behind the 
scenes. That’s why stakeholders and users (in B2B) are typically &lt;strong&gt;heavily attached to legacy systems&lt;/strong&gt;, despite all their well-known drawbacks and pains.&lt;/p&gt;&lt;p&gt;To
 most people, because such systems are at the very heart of the 
business, operating on them seems to be extremely risky and will require
 a significant amount of &lt;strong&gt;caution and preparation&lt;/strong&gt;. 
Corporate users don’t want big risks. So instead of dismissing legacy 
entirely, we might start by gathering existing knowledge first.&lt;/p&gt;&lt;h3 id="map-existing-workflows-and-dependencies"&gt;Map Existing Workflows and Dependencies&lt;/h3&gt;&lt;p&gt;The
 best place to start is to understand how and where exactly legacy 
systems are in use. You might discover that some bits of the legacy 
systems are used all over the place — not only in your product, but also
 in business dashboards, by external agencies, and by other companies 
that integrate your product into their services.&lt;/p&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://creative.navy/case-studies/ux-ui-design-technical-software-users"&gt;&lt;img alt="An overview of users’ behavior, frequency of use for features, and the complexity of the flow." height="464" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-improve-ux-legacy-systems/4-testing-session.jpg" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;Testing
 sessions to understand where users struggle, and how difficult tasks 
are to complete for them. From a fantastic case study by &lt;a href="https://creative.navy/case-studies/ux-ui-design-technical-software-users"&gt;CreativeNavy&lt;/a&gt;.&amp;nbsp;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;Very
 often, legacy systems have dependencies on their own, integrating other
 legacy systems that might be much older and in a much worse state. 
Chances are high that you might not even consider them in the big-bang 
redesign — mostly because you don’t know just &lt;strong&gt;how many black boxes&lt;/strong&gt; are in there.&lt;/p&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://creative.navy/case-studies/ux-ui-design-technical-software-users"&gt;&lt;img alt="An overview of users’ behavior, frequency of use for features, and the complexity of the flow." src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-improve-ux-legacy-systems/5-map-workflows-user-behavior.jpg" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;Map
 existing workflows by tracking user behavior, frequency, desired 
outcome, complexity, patterns, and user needs. From a fantastic case 
study by &lt;a href="https://creative.navy/case-studies/ux-ui-design-technical-software-users"&gt;CreativeNavy&lt;/a&gt;. (&lt;a href="https://files.smashing.media/articles/how-improve-ux-legacy-systems/5-map-workflows-user-behavior.jpg"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;Set up a board to &lt;a href="https://www.linkedin.com/pulse/breaking-down-complexity-task-analysis-ux-vitaly-friedman-sjt4f/"&gt;document current workflows and dependencies&lt;/a&gt; to get a better idea of how everything works together. Include stakeholders, and &lt;strong&gt;involve heavy users in the conversation&lt;/strong&gt;.
 You won’t be able to open the black box, but you can still shed some 
light on it from the perspectives of different people who may be relying
 on legacy for their work.&lt;/p&gt;&lt;figure&gt;&lt;a href="https://files.smashing.media/articles/how-improve-ux-legacy-systems/6-prioritizing-migrated-features.png"&gt;&lt;img alt="Prioritizing migrated features and features by impact and urgency." height="375" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-improve-ux-legacy-systems/6-prioritizing-migrated-features.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;Priorities matter. You won’t need to migrate everything, but you need to discover critical parts that must be migrated.&amp;nbsp;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;Once you’ve done that, set up a meeting to &lt;strong&gt;reflect to users and stakeholders&lt;/strong&gt;
 what you have discovered. You will need to build confidence and trust 
that you aren’t missing anything important, and you need to visualize 
the dependencies that a legacy tool has to everyone involved.&lt;/p&gt;&lt;p&gt;Replacing a legacy system is &lt;strong&gt;never about legacy alone&lt;/strong&gt;. It’s about the dependencies and workflows that rely on it, too.&lt;/p&gt;&lt;h3 id="choose-your-ux-migration-strategy"&gt;Choose Your UX Migration Strategy&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/04/legacy-systems/#choose-your-ux-migration-strategy"&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Once you have a &lt;strong&gt;big picture&lt;/strong&gt;
 in front of you, you need to decide on what to do next. Big-bang 
relaunch or a small upgrade? Which approach would work best? You might &lt;strong&gt;consider the following options&lt;/strong&gt; before you decide on how to proceed:&lt;/p&gt;&lt;figure&gt;&lt;a href="https://files.smashing.media/articles/how-improve-ux-legacy-systems/7-legacy-migration-strategies.jpg"&gt;&lt;img alt="A diagram titled ‘Legacy Migration Strategies’, showing five different approaches to migrating from an old system to a new system using arrows and descriptions." height="804" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-improve-ux-legacy-systems/7-legacy-migration-strategies.jpg" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;The
 different legacy migration strategies. You never migrate just a system —
 you also migrate workflows, habits, processes, and ways of working.&lt;/figcaption&gt;&lt;/figure&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Big-bang relaunch&lt;/strong&gt;.&lt;br /&gt;Sometimes
 the only available option, but it’s very risky, expensive, and can take
 years, without any improvements to the existing setup in the meantime.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Incremental migration&lt;/strong&gt;.&lt;br /&gt;Slowly retire pieces of legacy by replacing small bits with new designs. This offers quicker wins in a &lt;code&gt;Frankenstein&lt;/code&gt; style but can make the system unstable.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Parallel migration&lt;/strong&gt;.&lt;br /&gt;Run
 a public beta of the replacement alongside the legacy system to involve
 users in shaping the new design. Retire the old system when the new one
 is stable, but be prepared for the cost of maintaining both.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Incremental parallel migration&lt;/strong&gt;.&lt;br /&gt;List
 all business requirements the legacy system fulfills, then build a new 
product to meet them reliably, matching the old system from day one. 
Test early with power users, possibly offering an option to switch 
systems until the old one is fully retired.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Legacy UI upgrade + public beta&lt;/strong&gt;.&lt;br /&gt;Perform
 low-risk fine-tuning on the legacy system to align UX, while 
incrementally building a new system with a public beta. This yields 
quicker and long-term wins, ideal for fast results.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Replacing
 a system that has been carefully refined and heavily customized for a 
decade is a monolithic task. You can’t just rebuild something from 
scratch within a few weeks that others have been working on for years.&lt;/p&gt;&lt;p&gt;So whenever possible, try to &lt;strong&gt;increment gradually&lt;/strong&gt;, involving users and stakeholders and engineers along the way — and with enough &lt;strong&gt;buffer time&lt;/strong&gt; and &lt;strong&gt;continuous feedback loops&lt;/strong&gt;.&lt;/p&gt;&lt;h2 id="wrapping-up"&gt;Wrapping Up&lt;/h2&gt;&lt;p&gt;With legacy projects, failure is often not an option. You’re migrating not just components, but &lt;strong&gt;users and workflows&lt;/strong&gt;. Because you operate on the &lt;strong&gt;very heart of the business&lt;/strong&gt;, expect a lot of attention, skepticism, doubts, fears, and concerns. So build &lt;strong&gt;strong relationships&lt;/strong&gt;
 with key stakeholders and key users and share ownership with them. You 
will need their support and their buy-in to bring your UX work in 
action.&lt;/p&gt;&lt;p&gt;Stakeholders will request old and new features. They will focus on &lt;strong&gt;edge cases, exceptions, and tiny tasks&lt;/strong&gt;.
 They will question your decisions. They will send mixed signals and 
change their opinions. And they will expect the new system to run 
flawlessly from day one.&lt;/p&gt;&lt;p&gt;And the best thing you can do is to work 
with them throughout the entire design process, right from the very 
beginning. Run a successful pilot project to &lt;strong&gt;build trust&lt;/strong&gt;. Report your progress repeatedly. And account for &lt;strong&gt;intense phases of rigorous testing&lt;/strong&gt; with legacy users.&lt;/p&gt;&lt;p&gt;Revamping
 a legacy system is a tough challenge. But there is rarely any project 
that can have so much impact on such a scale. Roll up your sleeves and 
get through it successfully, and your team will be &lt;strong&gt;remembered, respected, and rewarded&lt;/strong&gt; for years to come.&lt;/p&gt;&lt;div class="book-cta__inverted"&gt;&lt;div class="book-cta" data-handler="ContentTabs" data-mq="(max-width: 480px)"&gt;&lt;div class="book-cta__col book-cta__hardcover content-tab--content"&gt;&lt;h3 class="book-cta__title"&gt;&lt;span&gt;Video + UX Training&lt;/span&gt;&lt;/h3&gt;&lt;span class="book-cta__price"&gt;&lt;span&gt;&lt;span&gt;&lt;span class="currency-sign"&gt;$&lt;/span&gt;&amp;nbsp;&lt;span&gt;495&lt;sup class="sup"&gt;.00&lt;/sup&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class="book-cta__price--old"&gt;&lt;span class="currency-sign"&gt;$&lt;/span&gt;&amp;nbsp;&lt;span&gt;799&lt;sup class="sup"&gt;.00&lt;/sup&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;a class="btn btn--full btn--medium btn--text-shadow" href="https://smart-interface-design-patterns.thinkific.com/enroll/3081832?price_id=3951439"&gt;Get Video + UX Training&lt;div&gt;&lt;/div&gt;&lt;/a&gt;&lt;p class="book-cta__desc"&gt;25 video lessons (8h) + &lt;a href="https://smashingconf.com/online-workshops/workshops/vitaly-friedman-impact-design/"&gt;Live UX Training&lt;/a&gt;.&lt;br /&gt;100 days money-back-guarantee.&lt;/p&gt;&lt;/div&gt;&lt;div class="book-cta__col book-cta__ebook content-tab--content"&gt;&lt;h3 class="book-cta__title"&gt;&lt;span&gt;Video only&lt;/span&gt;&lt;/h3&gt;&lt;div data-audience="anonymous free supporter" data-remove="true"&gt;&lt;span class="book-cta__price" data-handler="PriceTag"&gt;&lt;span&gt;&lt;span&gt;&lt;span class="currency-sign"&gt;$&lt;/span&gt;&amp;nbsp;&lt;span&gt;250&lt;sup class="sup"&gt;.00&lt;/sup&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="book-cta__price--old"&gt;&lt;span class="currency-sign"&gt;$&lt;/span&gt;&amp;nbsp;&lt;span&gt;350&lt;sup class="sup"&gt;.00&lt;/sup&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;a class="btn btn--full btn--medium btn--text-shadow" href="https://smart-interface-design-patterns.thinkific.com/enroll/3081832?price_id=3950630"&gt;Get the video course&lt;div&gt;&lt;/div&gt;&lt;/a&gt;&lt;p class="book-cta__desc" data-audience="anonymous free supporter" data-remove="true"&gt;25 video lessons (8h). Updated yearly.&lt;br /&gt;Also available as a &lt;a href="https://smart-interface-design-patterns.thinkific.com/enroll/3570306?price_id=4503439"&gt;UX Bundle with 3 video courses.&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;h2 id="useful-resources"&gt;Useful Resources&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://blog.scottlogic.com/2021/07/16/UX-Migration-Strategy.html"&gt;UX Migration Strategy For Legacy Apps&lt;/a&gt;, by Tamara Chehayeb Makarem&lt;/li&gt;&lt;li&gt;&lt;a href="https://uxdesign.cc/to-improve-legacy-systems-sometimes-you-need-to-take-a-restoration-mindset-d72f7b69442f?sk=v2%2F524df15a-3aca-48f6-adff-98588a64bda0"&gt;How To Improve Legacy Systems&lt;/a&gt;, by Christopher Wong&lt;/li&gt;&lt;li&gt;&lt;a href="https://medium.com/enterprise-ux/designing-with-legacy-d0e4bef0d9ea"&gt;Designing With Legacy&lt;/a&gt;, by Peter Zalman&lt;/li&gt;&lt;li&gt;&lt;a href="https://medium.com/design-bootcamp/redesigning-a-legacy-system-for-a-large-organisation-5089429f7e2e"&gt;Redesigning A Large Legacy System&lt;/a&gt;, by Pawel Halicki&lt;/li&gt;&lt;li&gt;&lt;a href="https://understandlegacycode.com"&gt;How To Manage Legacy Code&lt;/a&gt;, by Nicolas Carlo&lt;/li&gt;&lt;li&gt;&lt;a href="https://www.koruux.com/blog/transforming-legacy-system/"&gt;How To Transform Legacy&lt;/a&gt;, by Bansi Mehta&lt;/li&gt;&lt;li&gt;&lt;a href="https://www.debt.design/"&gt;Design Debt 101&lt;/a&gt;, by Alicja Suska&lt;/li&gt;&lt;li&gt;&lt;a href="https://www.linkedin.com/posts/vitalyfriedman_ux-enterprise-activity-7128696386841120769-VcPD"&gt;Practical Guide To Enterprise UX&lt;/a&gt;, by Yours Truly&lt;/li&gt;&lt;li&gt;&lt;a href="https://www.linkedin.com/posts/vitalyfriedman_ux-design-healthcare-activity-7124347175395815424-Q8Xn"&gt;Healthcare UX Design Playbook&lt;/a&gt;, by Yours Truly&lt;/li&gt;&lt;/ul&gt;</description><link>http://honeyvig.blogspot.com/2026/04/how-to-improve-ux-in-legacy-systems.html</link><author>noreply@blogger.com (H)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-9165069509664255576.post-6078493634285266707</guid><pubDate>Mon, 27 Apr 2026 06:44:00 +0000</pubDate><atom:updated>2026-04-26T23:44:42.395-07:00</atom:updated><title>Session Timeouts: The Overlooked Accessibility Barrier In Authentication Design</title><description>&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="c-garfield-summary"&gt;&lt;section aria-label="Quick summary" class="article__summary"&gt;Poorly
 handled session timeouts are more than a technical inconvenience. They 
can become serious accessibility barriers that interrupt essential 
online tasks, especially for people with disabilities. Here is how to 
implement thoughtful session management that improves usability, reduces
 frustration, and helps create a more accessible and respectful web.&lt;/section&gt;&lt;/div&gt;&lt;p&gt;For
 web professionals, session management is a balancing act between user 
experience, cybersecurity, and resource usage. For people with 
disabilities, it is more than that — it is a barrier to buying digital 
tickets, scrolling on social media, or applying for a loan online. &lt;strong&gt;Session timeout accessibility&lt;/strong&gt; can be the difference between a bad day and a good day for those with disabilities.&lt;/p&gt;&lt;p&gt;For
 many, getting halfway through an important form only to be 
unceremoniously kicked back to the login screen is a common experience. 
Such incidents can lead to exasperation and even abandonment of the 
website entirely. With some backend work, web professionals can ensure 
no one has to experience this frustration.&lt;/p&gt;&lt;h2 id="why-session-timeouts-disproportionately-affect-users-with-disabilities"&gt;Why Session Timeouts Disproportionately Affect Users With Disabilities&lt;/h2&gt;&lt;p&gt;A considerable portion of the global population has cognitive, motor, or vision impairments. Worldwide, &lt;a href="https://designerly.com/mobile-app-accessibility-checklist/"&gt;around 1.3 billion people&lt;/a&gt;
 have significant disabilities. Whether they possess motor, cognitive, 
or visual impairments, their disabilities affect their ability to 
interact with technology easily. They can all be disproportionately 
affected by session timeouts, making session timeout accessibility a 
critical issue.&lt;/p&gt;&lt;p&gt;Session timeouts are inaccessible for a large percentage of the population. An &lt;a href="https://www.hanoversearch.com/blog/inclusive-recruitment-a-focus-on-neurodiverse-talent/"&gt;estimated 20% of people are&lt;/a&gt; neurodivergent, meaning timeout barriers don’t just affect a small subset of users — they impact a &lt;strong&gt;substantial portion of any website’s audience&lt;/strong&gt;. As a result, some users may look inactive when they are not. &lt;strong&gt;Strict timeouts create undue pressure.&lt;/strong&gt;&lt;/p&gt;&lt;h3 id="motor-impairments-and-slower-input-speeds"&gt;Motor Impairments and Slower Input Speeds&lt;/h3&gt;&lt;p&gt;For
 instance, someone with cerebral palsy tries to purchase tickets online 
for an upcoming concert. Due to coordination difficulties and muscle 
stiffness, they may enter their information more slowly than a 
non-disabled person would. They select the date, choose their seats, and
 fill out personal information. Before they can enter their credit card 
details, a timeout pop-up appears. They have been logged out due to 
“inactivity” and must restart the entire process.&lt;/p&gt;&lt;p&gt;This situation 
is not entirely hypothetical. Matthew Kayne is a disability rights 
advocate, broadcaster, and contributor to The European magazine. He 
describes the effort required to navigate websites as someone with 
cerebral palsy. He explains how the user interface &lt;a href="https://the-european.eu/story-53902/this-one-digital-glitch-is-pushing-disabled-people-to-breaking-point.html"&gt;is often poorly designed&lt;/a&gt;
 for adaptive devices, and he worries his equipment won’t respond 
correctly. After carefully navigating each page, he is suddenly logged 
out. In a moment, one timed form can erase hours of work, and it’s not 
just a matter of inconvenience. A single failed attempt can delay 
support or cause him to miss appointments.&lt;/p&gt;&lt;p&gt;Motor impairments can &lt;strong&gt;slow input speed&lt;/strong&gt;,
 making it appear the user is not at their computer. As such, people who
 experience stiffness, hand tremors, coordination challenges, 
involuntary movements, or muscle weakness are disproportionately 
affected by session timeouts. According to the DWP Accessibility Manual,
 it &lt;a href="https://accessibility-manual.dwp.gov.uk/tools-and-resources/basic-accessibility-checks/10-session-timeouts-impact-on-users"&gt;can take multiple attempts&lt;/a&gt;
 for adaptive technology to register input, slowing users down 
considerably. Even if they receive a warning, they may not be able to 
act fast enough to prove they are still active.&lt;/p&gt;&lt;h3 id="cognitive-impairments-and-processing-time"&gt;Cognitive Impairments and Processing Time&lt;/h3&gt;&lt;p&gt;Session
 timeouts can also create accessibility barriers for those with various 
types of cognitive differences. Strict timeouts can create undue 
pressure that assumes everyone processes information at the same speed. 
Users may appear inactive when they are actually reading, thinking, or 
processing.&lt;/p&gt;&lt;p&gt;Cognitive differences encompass a wide range of 
experiences, including neurodivergences like autism and ADHD, 
developmental disabilities like Down syndrome, and learning disabilities
 like dyslexia. Many people are born with cognitive differences. In 
fact, an &lt;a href="https://www.hanoversearch.com/blog/inclusive-recruitment-a-focus-on-neurodiverse-talent/"&gt;estimated 20% of people are&lt;/a&gt;
 neurodivergent, making up a large portion of any website’s audience. 
Others acquire cognitive disabilities later in life through traumatic 
brain injury or conditions like dementia.&lt;/p&gt;&lt;p&gt;People with cognitive 
disabilities often need more time to complete online tasks — not because
 of any deficit, but because they process information differently. 
Design choices that work well for neurotypical users can create 
unnecessary obstacles for people with ADHD, dyslexia, autism, or 
memory-related conditions.&lt;/p&gt;&lt;p&gt;Invisible session timeouts are 
particularly problematic for people who experience memory loss, language
 processing differences, or &lt;strong&gt;time blindness&lt;/strong&gt;. For example, neurodivergent technology leader Kate Carruthers says ADHD &lt;a href="https://katecarruthers.com/life-with-adhd-time-blindness-or-why-i-lose-hours-not-just-my-keys/"&gt;has affected her perception&lt;/a&gt; of time. She has time blindness and can’t reliably track how much time has passed, making estimates unhelpful.&lt;/p&gt;&lt;blockquote class="pull-quote"&gt;&lt;p&gt;&lt;a aria-label="Share on Twitter" class="pull-quote__link" href="https://twitter.com/share?text=%0aWhen%20websites%20depend%20on%20users%20estimating%20remaining%20time%20before%20a%20session%20expires,%20they%20quietly%20exclude%20people%20%e2%80%94%20not%20just%20those%20with%20formal%20ADHD%20diagnoses,%20but%20anyone%20who%20experiences%20time%20differently%20or%20processes%20information%20at%20a%20different%20pace.%0a&amp;amp;url=https://smashingmagazine.com%2f2026%2f04%2fsession-timeouts-accessibility-barrier-authentication-design%2f"&gt;When
 websites depend on users estimating remaining time before a session 
expires, they quietly exclude people — not just those with formal ADHD 
diagnoses, but anyone who experiences time differently or processes 
information at a different pace.&lt;/a&gt;&lt;/p&gt;&lt;div class="pull-quote__quotation"&gt;&lt;div class="pull-quote__bg"&gt;&lt;span class="pull-quote__symbol"&gt;“&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;h3 id="vision-impairments-and-screen-reader-navigation-overhead"&gt;Vision Impairments and Screen Reader Navigation Overhead&lt;/h3&gt;&lt;p&gt;Since
 blind or low-vision users cannot visually scan a page to find what they
 need, they must listen to links, headings, and form fields, which is 
inherently &lt;strong&gt;more time-consuming&lt;/strong&gt;. More than &lt;a href="https://int.livhospital.com/complete-top-5-reasons-for-vision-loss-worldwide/"&gt;43 million people worldwide&lt;/a&gt;
 are affected by blindness, while 295 million have moderate to severe 
vision impairment, which makes this a significant accessibility concern 
for any global-facing website.&lt;/p&gt;&lt;p&gt;As a result, these users’ sessions may expire even if they are active. &lt;strong&gt;Live timers and 30-second warnings do little to help&lt;/strong&gt;, as they are not built with screen readers in mind.&lt;/p&gt;&lt;p&gt;Bogdan
 Cerovac, a web developer passionate about digital accessibility, 
experienced this firsthand. The countdown timer informed him how long he
 had left before being logged out due to inactivity. By all accounts, it
 worked fine. However, he describes the &lt;a href="https://cerovac.com/a11y/2025/07/countdowns-and-timers-forgotten-detail-that-can-make-your-users-really-hate-your-product/"&gt;screen reader experience as horrible&lt;/a&gt;,
 as it notified him of the remaining time every single second. He 
couldn’t navigate the page because he was spammed by constant status 
messages.&lt;/p&gt;&lt;h2 id="common-timeout-patterns-that-fail-accessibility-requirements"&gt;Common Timeout Patterns That Fail Accessibility Requirements&lt;/h2&gt;&lt;p&gt;According to the National Institute of Standards and Technology, &lt;a href="https://pages.nist.gov/800-63-4/sp800-63b/session/"&gt;session management is preferable&lt;/a&gt;
 to continually preserving credentials, which would incentivize users to
 create authentication workarounds that could threaten security. 
However, several common timeout patterns fail to meet modern standards 
for session timeout accessibility.&lt;/p&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://files.smashing.media/articles/session-timeouts-accessibility-barrier-authentication-design/1-timeout-pattern-fail-accessibility.png"&gt;&lt;img alt="A session expired window with a “Back to main page” button." height="480" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/session-timeouts-accessibility-barrier-authentication-design/1-timeout-pattern-fail-accessibility.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;Image source: &lt;a href="https://github.com/alfio-event/alf.io/issues/903"&gt;princekwame&lt;/a&gt;.&lt;/figcaption&gt;&lt;/figure&gt;&lt;h3 id="silent-timeouts-and-insufficient-warnings"&gt;Silent Timeouts and Insufficient Warnings&lt;/h3&gt;&lt;p&gt;Many
 websites either provide no warning before logging users out, or they 
display a brief, seconds-long pop-up that appears too late to be 
actionable. For users who navigate via screen reader, these warnings may
 not be announced in time. For those with motor impairments, a 30-second
 countdown may not provide enough time to respond.&lt;/p&gt;&lt;p&gt;Let’s consider 
the Consular Electronic Application Center’s DS-260 page, which is used 
to apply for or renew U.S. nonimmigrant visas. If an application &lt;a href="https://travel.state.gov/content/travel/en/us-visas/visa-information-resources/forms/online-immigrant-visa-forms/ds-260-faqs.html"&gt;is idle for around 20 minutes&lt;/a&gt;,
 it will log the user off without warning. The FAQ page only provides an
 approximate time estimate. Someone’s work only saves when they complete
 the page, so they may lose significant progress.&lt;/p&gt;&lt;h3 id="nonextendable-sessions"&gt;Nonextendable Sessions&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/04/session-timeouts-accessibility-barrier-authentication-design/#nonextendable-sessions"&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;An
 abrupt “session expired” message is frustrating even for individuals 
without disabilities. If there is no option to continue, users are 
forced to log back in and restart their work, wasting time and energy.&lt;/p&gt;&lt;h3 id="form-data-loss-on-expiration"&gt;Form Data Loss on Expiration&amp;nbsp;&lt;/h3&gt;&lt;p&gt;Unless
 the website automatically saves progress, visitors will lose everything
 when the session expires. For someone with disabilities, this does not 
simply waste time. It can make their day immeasurably harder. Imagine 
spending an hour on a service request, job application, or purchase 
order only for all progress to be completely erased with little to no 
warning.&lt;/p&gt;&lt;h2 id="design-patterns-that-balance-security-and-accessibility"&gt;Design Patterns That Balance Security and Accessibility&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/04/session-timeouts-accessibility-barrier-authentication-design/#design-patterns-that-balance-security-and-accessibility"&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Inconsistent
 timeout periods and a lack of warnings lead to the sudden, unexpected 
loss of all unsaved work. For long, complex forms, like the DS-260, a 
poor user experience is extremely frustrating. In comparison, the United
 Kingdom’s application for pension credit is highly accessible. It warns
 users &lt;a href="https://design-system.dwp.gov.uk/patterns/manage-a-session-timeout"&gt;at least two minutes&lt;/a&gt;
 in advance and allows them to extend the session. It meets level AA of 
the WCAG 2.2 success criteria, indicating its accessibility.&lt;/p&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://files.smashing.media/articles/session-timeouts-accessibility-barrier-authentication-design/2-timeout-pattern-accessibility.png"&gt;&lt;img alt="A tab session expired window with a refresh button." height="450" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/session-timeouts-accessibility-barrier-authentication-design/2-timeout-pattern-accessibility.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;Image source: &lt;a href="https://experienceleaguecommunities.adobe.com/adobe-workfront-23/pop-up-message-saying-session-has-expired-129862"&gt;Experience League&lt;/a&gt;.&amp;nbsp;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;People
 with disabilities are disproportionately affected by the unintended 
consequences of poor session management. Thankfully, session timeouts’ 
inaccessibility is not a matter of fact. With a few small changes, web 
professionals can significantly improve their website’s accessibility.&lt;/p&gt;&lt;h3 id="advance-warning-systems-and-extend-functionality"&gt;Advance Warning Systems and Extend Functionality&lt;/h3&gt;&lt;p&gt;Websites
 should clearly state the time limit’s existence and duration before the
 session starts. For instance, if someone is filling out a bank form, 
the first page should exist solely to inform them that it has a 
60-minute time limit. A live counter that updates regularly can help 
them track how much time remains. Also, users should be told whether 
they can adjust the session timeout length.&lt;/p&gt;&lt;h3 id="activity-based-vs-absolute-timeouts"&gt;Activity-Based vs. Absolute Timeouts&lt;/h3&gt;&lt;p&gt;An
 activity-based timeout logs users out due to inactivity, while an 
absolute timeout logs them out regardless of activity. For an office, a 
24-hour absolute timer might make sense, since workers only need to log 
in when they get to work. As long as users know when their session will 
expire, the latter is more accessible than the former.&lt;/p&gt;&lt;h3 id="auto-save-and-progress-preservation"&gt;Auto-Save and Progress Preservation&lt;/h3&gt;&lt;p&gt;Cookies,
 localStorage, and sessionStorage are temporary, client-side storage 
mechanisms that allow web applications to store data for the duration of
 a single browser session. They are powerful, lightweight tools. Web 
developers can use them to automatically save users’ progress at 
frequent intervals, ensuring data is restored upon reauthentication.&lt;/p&gt;&lt;p&gt;This
 way, even if someone’s session expires by accident, they are not 
penalized. Once they log back in, they can finish filling out their 
credit card details or pick up where they left off with an online form.&lt;/p&gt;&lt;h2 id="testing-and-wcag-compliance-considerations"&gt;Testing and WCAG Compliance Considerations&lt;/h2&gt;&lt;p&gt;The
 Web Content Accessibility Guidelines (WCAG) is a collection of 
internationally accepted internet accessibility standards published by 
the W3C. It acts as the arbiter of session timeout accessibility. Web 
developers should pay special attention to &lt;strong&gt;Guideline 2.9.2&lt;/strong&gt;, &lt;a href="https://www.w3.org/TR/wcag-3.0/#adequate-time"&gt;which outlines best practices for adequate&lt;/a&gt; time.&lt;/p&gt;&lt;p&gt;The &lt;strong&gt;timeout adjustable mechanism&lt;/strong&gt;
 should extend the time limit before the session expires or allow it to 
be turned off completely. For the former option, a dialog box should 
appear asking users if they need more time, allowing them to continue 
with one click. The WC3 notes that exceptions exist.&lt;/p&gt;&lt;p&gt;For example, 
when a website conducts a live ticket sale, users can only hold tickets 
in their carts for 10 minutes to give others a chance to purchase 
limited inventory. Alternatively, session timeouts may be necessary on 
shared computers. If librarians allowed everyone to stay logged in 
instead of automatically signing them out overnight, they would risk 
security issues.&lt;/p&gt;&lt;p&gt;Some processes should not have time limits at 
all. When browsing social media, reading a news article, or searching 
for items on an e-commerce site, there is no reason a session should 
expire within an arbitrary time frame. Meanwhile, in a timed exam, it 
may be necessary. However, in this case, administrators can extend time 
limits for students with disabilities.&lt;/p&gt;&lt;p&gt;When web developers make session management accessible, they are not catering to a small group. Pew Research Center data shows &lt;a href="https://www.pewresearch.org/short-reads/2021/09/10/americans-with-disabilities-less-likely-than-those-without-to-own-some-digital-devices/"&gt;62% of adults with disabilities&lt;/a&gt;
 own a computer. 72% have high-speed home internet. These figures do not
 differ statistically from the percentage of non-disabled adults who say
 the same.&lt;/p&gt;&lt;h2 id="overcoming-the-session-timeout-accessibility-barrier"&gt;Overcoming the Session Timeout Accessibility Barrier&lt;/h2&gt;&lt;p&gt;The WCAG provides additional resources that web developers can review to understand session management accessibility better:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://www.w3.org/TR/UNDERSTANDING-WCAG20/time-limits-required-behaviors.html"&gt;WCAG SC 2.2.1 Timing Adjustable&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://www.w3.org/TR/UNDERSTANDING-WCAG20/time-limits-server-timeout.html"&gt;WCAG SC 2.2.5 Re-authenticating&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://www.w3.org/WAI/WCAG22/Understanding/timeouts.html"&gt;WCAG SC 2.2.6 Timeouts&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;In
 addition to following these guidelines, there is a wealth of 
information from leading educational institutions, authorities on open 
web technologies, and government agencies. They provide a great starting
 place for those with intermediate web development knowledge.&lt;/p&gt;&lt;p&gt;Web 
professionals should consider the following resources to learn more 
about tools and techniques they can use to make session management more 
accessible:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://accessibility.huit.harvard.edu/technique-session-extension"&gt;Harvard University’s Session Extension Technique&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://accessibility-manual.dwp.gov.uk/tools-and-resources/basic-accessibility-checks/10-session-timeouts-how-to-test"&gt;DWP Accessibility Manual: How to test session timeouts&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage"&gt;Window: sessionStorage property&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;blockquote class="pull-quote"&gt;&lt;p&gt;&lt;a aria-label="Share on Twitter" class="pull-quote__link" href="https://twitter.com/share?text=%0aSession%20timeout%20accessibility%20is%20not%20only%20an%20industry%20best%20practice%20but%20an%20ethical%20web%20development%20standard.%0a&amp;amp;url=https://smashingmagazine.com%2f2026%2f04%2fsession-timeouts-accessibility-barrier-authentication-design%2f"&gt;Session timeout accessibility is not only an industry best practice but an ethical web development standard.&lt;/a&gt;&lt;/p&gt;&lt;div class="pull-quote__quotation"&gt;&lt;div class="pull-quote__bg"&gt;&lt;span class="pull-quote__symbol"&gt;“&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;p&gt;Those who prioritize it will appeal to a wider audience, &lt;strong&gt;improve usability&lt;/strong&gt;, and attract more website visitors and longer sessions.&lt;/p&gt;&lt;p&gt;The
 main takeaway is that a website with inaccessible session timeouts 
sends a clear message that it doesn’t value the user’s time or effort, a
 problem that creates significant barriers for people with disabilities.
 However, this is a solvable issue. With a few simple changes, such as 
providing session extension warnings and auto-saving progress, web 
developers can build a more considerate, accessible, and respectful 
internet for everyone.&lt;/p&gt;</description><link>http://honeyvig.blogspot.com/2026/04/session-timeouts-overlooked.html</link><author>noreply@blogger.com (H)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-9165069509664255576.post-5801852115429374999</guid><pubDate>Sat, 25 Apr 2026 06:10:00 +0000</pubDate><atom:updated>2026-04-24T23:14:25.511-07:00</atom:updated><title>The UX Designer’s Nightmare: When “Production-Ready” Becomes A Design Deliverable</title><description>&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="c-garfield-summary"&gt;&lt;section aria-label="Quick summary" class="article__summary"&gt;In
 a rush to embrace AI, the industry is redefining what it means to be a 
UX designer, blurring the line between design and engineering. Carrie 
Webster explores what’s gained, what’s lost, and why designers need to 
remain the guardians of the user experience.&lt;/section&gt;&lt;/div&gt;&lt;p&gt;In early 2026, I noticed that the UX designer’s toolkit seemed to shift overnight. The industry standard &lt;i&gt;“Should designers code?”&lt;/i&gt;
 debate was abruptly settled by the market, not through a consensus of 
our craft, but through the brute force of job requirements. If you 
browse LinkedIn today, you’ll notice a stark change: UX roles 
increasingly demand &lt;b&gt;&lt;a href="https://www.refontelearning.com/blog/ui-ux-designer-engineering-in-2026-crafting-future-ready-user-experiences"&gt;AI-augmented development&lt;/a&gt;&lt;/b&gt;, &lt;b&gt;technical orchestration,&lt;/b&gt; and &lt;b&gt;production-ready prototyping.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;For
 many, including myself, this is the ultimate design job nightmare. We 
are being asked to deliver both the “vibe” and the “code” 
simultaneously, using AI agents to bridge a technical gap that 
previously took years of computer science knowledge and coding 
experience to cross. But as the industry rushes to meet these new 
expectations, they are discovering that AI-generated functional code is 
not always &lt;i&gt;good&lt;/i&gt; code.&lt;/p&gt;&lt;h2 id="the-linkedin-pressure-cooker-role-creep-in-2026"&gt;The LinkedIn Pressure Cooker: Role Creep In 2026&lt;/h2&gt;&lt;p&gt;The job market is sending a clear signal. While traditional graphic design roles are expected to grow by only &lt;b&gt;3%&lt;/b&gt; through 2034, UX, UI, and &lt;a href="https://www.nobledesktop.com/careers/designer/job-outlook#:~:text=The%20projected%20future%20growth%20figures%20for%20Digital,job%20growth%20(which%20lies%20somewhere%20around%205%25)."&gt;Product Design roles&lt;/a&gt; are projected to grow by &lt;b&gt;16%&lt;/b&gt; over the same period.&lt;/p&gt;&lt;p&gt;However, this growth is increasingly tied to the rise of &lt;b&gt;AI product development&lt;/b&gt;,
 where “design skills” have recently become the #1 most in-demand 
capability, even ahead of coding and cloud infrastructure. Companies 
building these platforms are no longer just looking for visual 
designers; they need professionals who can “&lt;a href="https://humbldesign.io/blog-posts/will-ai-replace-designers-2026"&gt;translate technical capability into human-centered experiences&lt;/a&gt;.”&lt;/p&gt;&lt;p&gt;This
 creates a high-stakes environment for the UX designer. We are no longer
 just responsible for the interface; we are expected to understand the 
technical logic well enough to ensure that complex AI capabilities feel 
intuitive, safe, and useful for the human on the other side of the 
screen. Designers are being pushed toward a &lt;b&gt;“design engineer” model&lt;/b&gt;, where we must bridge the gap between abstract &lt;a href="https://www.refontelearning.com/blog/ui-ux-designer-engineering-in-2026-crafting-future-ready-user-experiences#skills-and-competencies-for-the-2026-uiux-designer-3"&gt;AI logic and user-facing code&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;A &lt;a href="https://www.lyssna.com/blog/ux-design-trends/"&gt;recent survey&lt;/a&gt; found that &lt;b&gt;73% of designers&lt;/b&gt;
 now view AI as a primary collaborator rather than just a tool. However,
 this “collaboration” often looks like “role creep.” Recruiters are 
often not just looking for someone who understands user empathy and 
information architecture — they want someone who can also prompt a React
 component into existence and push it to a repository!&lt;/p&gt;&lt;p&gt;This shift has created a &lt;b&gt;competency gap&lt;/b&gt;.&lt;/p&gt;&lt;blockquote&gt;As
 an experienced senior designer who has spent decades mastering the 
nuances of cognitive load, accessibility standards, and ethnographic 
research, I am suddenly finding myself being judged on my ability to 
debug a CSS Flexbox issue or manage a Git branch.&lt;/blockquote&gt;&lt;p&gt;The nightmare isn’t the technology itself. It’s the &lt;b&gt;reallocation of value&lt;/b&gt;.&lt;/p&gt;&lt;blockquote class="pull-quote"&gt;&lt;p&gt;&lt;a aria-label="Share on Twitter" class="pull-quote__link" href="https://twitter.com/share?text=%0aBusinesses%20are%20beginning%20to%20value%20the%20speed%20of%20output%20over%20the%20quality%20of%20the%20experience,%20fundamentally%20changing%20what%20it%20means%20to%20be%20a%20%e2%80%9csuccessful%e2%80%9d%20designer%20in%202026.%0a&amp;amp;url=https://smashingmagazine.com%2f2026%2f04%2fproduction-ready-becomes-design-deliverable-ux%2f"&gt;Businesses
 are beginning to value the speed of output over the quality of the 
experience, fundamentally changing what it means to be a “successful” 
designer in 2026.&lt;/a&gt;&lt;/p&gt;&lt;div class="pull-quote__quotation"&gt;&lt;div class="pull-quote__bg"&gt;&lt;span class="pull-quote__symbol"&gt;“&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://files.smashing.media/articles/ux-designer-nightmare-production-ready-becomes-design-deliverable/1-figma.jpg"&gt;&lt;img alt="Figma to AI code ad" height="450" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ux-designer-nightmare-production-ready-becomes-design-deliverable/1-figma.jpg" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;Tools that allow designers to switch from design to code. (Image source: &lt;a href="https://www.figma.com/community/plugin/1443774571835235184/figma-to-ai-code-by-designcode"&gt;Figma&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;h3 id="the-competence-trap-two-job-skill-sets-one-average-result"&gt;The Competence Trap: Two Job Skill Sets, One Average Result&lt;/h3&gt;&lt;p&gt;There
 is potentially a very dangerous myth circulating in boardrooms that AI 
makes a designer “equal” to an engineer. This narrative suggests that 
because an LLM can generate a functional JavaScript event handler, the 
person prompting it doesn’t need to understand the underlying logic. In 
reality, attempting to master two disparate, deep fields simultaneously 
will most likely lead to being &lt;b&gt;averagely competent&lt;/b&gt; at both.&lt;/p&gt;&lt;h3 id="the-averagely-competent-dilemma"&gt;The “Averagely Competent” Dilemma&lt;/h3&gt;&lt;p&gt;For
 a senior UX designer to become a senior-level coder is like asking a 
master chef to also be a master plumber because “they both work in the 
kitchen.” You might get the water running, but you won’t know why the 
pipes are rattling.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;The “cognitive offloading” risk.&lt;/b&gt;&lt;br /&gt;Research
 shows that while AI can speed up task completion, it often leads to a 
significant decrease in conceptual mastery. In a controlled study, 
participants using AI assistance scored &lt;a href="https://www.psychologytoday.com/au/blog/the-asymmetric-brain/202602/cognitive-offloading-using-ai-reduces-new-skill-formation"&gt;17% lower&lt;/a&gt; on comprehension tests than those who coded by hand.&lt;/li&gt;&lt;li&gt;&lt;b&gt;The debugging gap.&lt;/b&gt;&lt;br /&gt;The largest performance gap between AI-reliant users and hand-coders is in &lt;a href="https://www.anthropic.com/research/AI-assistance-coding-skills"&gt;debugging&lt;/a&gt;. When a designer uses AI to write code they don’t fully understand, they don’t have the ability to identify &lt;i&gt;when&lt;/i&gt; and &lt;i&gt;why&lt;/i&gt; it fails.&lt;/li&gt;&lt;/ul&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://files.smashing.media/articles/ux-designer-nightmare-production-ready-becomes-design-deliverable/2-ai-assistance-coding-skills-speed.png"&gt;&lt;img alt="A chart showing how AI assistance impacts coding speed and skill formation" height="451" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ux-designer-nightmare-production-ready-becomes-design-deliverable/2-ai-assistance-coding-skills-speed.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;Using AI tools impedes coding skill formation. (Image source: &lt;a href="https://www.anthropic.com/research/AI-assistance-coding-skills"&gt;Anthropic&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;So,
 if a designer ships an AI-generated component that breaks during a 
high-traffic event and cannot manually trace the logic, they are no 
longer an expert. They are now a liability.&lt;/p&gt;&lt;h3 id="the-high-cost-of-unoptimised-code"&gt;The High Cost Of Unoptimised Code&lt;/h3&gt;&lt;p&gt;Any
 experienced code engineer will tell you that creating code with AI 
without the right prompt leads to a lot of rework. Because most 
designers lack the technical foundation to audit the code the AI gives 
them, they are inadvertently shipping massive amounts of &lt;a href="https://gocrossbridge.com/blog/ai-generated-code/"&gt;“Quality Debt”&lt;/a&gt;.&lt;/p&gt;&lt;h2 id="common-issues-in-designer-generated-ai-code"&gt;Common Issues In Designer-Generated AI Code&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;The security flaw&lt;/b&gt;&lt;br /&gt;Recent reports indicate that up to &lt;a href="https://www.sherlockforensics.com/pages/ai-code-security-report-2026.html"&gt;92% of AI-generated codebases&lt;/a&gt;
 contain at least one critical vulnerability. A designer might see a 
functioning login form, unaware that it has an 86% failure rate in XSS 
defense, which are the security measures aimed at preventing attackers 
from injecting malicious scripts into trusted websites.&lt;/li&gt;&lt;li&gt;&lt;b&gt;The accessibility illusion&lt;/b&gt;&lt;br /&gt;AI
 often generates “functional” applications that lack semantic integrity.
 A designer might prompt a “beautiful and functional toggle switch,” but
 the AI may provide a non-semantic &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; that lacks keyboard focus and screen-reader compatibility, creating &lt;a href="https://www.levelaccess.com/blog/accessibility-debt-in-software-development-and-how-to-engineer-it-out/"&gt;Accessibility Debt&lt;/a&gt; that is expensive to fix later.&lt;/li&gt;&lt;li&gt;&lt;b&gt;The performance penalty&lt;/b&gt;&lt;br /&gt;AI-generated code tends to be verbose. AI is linked to &lt;a href="https://www.netcorpsoftwaredevelopment.com/blog/ai-generated-code-statistics"&gt;4x more code duplication&lt;/a&gt;
 than human-written code. This verbosity slows down page loads, creates 
massive CSS files, and negatively impacts SEO. To a business, the task 
looks “done.” To a user with a slow connection or a screen reader, the 
site is a nightmare.&lt;/li&gt;&lt;/ul&gt;&lt;h2 id="creating-more-work-not-less"&gt;Creating More Work, Not Less&lt;/h2&gt;&lt;p&gt;The promise of AI was that designers could ship features without bothering the engineers. The reality has been the birth of a &lt;b&gt;“Rework Tax”&lt;/b&gt; that is draining engineering resources across the industry.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Cleaning up&lt;/b&gt;&lt;br /&gt;Organisations are finding that while velocity increases, incidents per Pull Request are also rising by &lt;a href="https://blog.exceeds.ai/ai-code-analysis-benchmark-reports/"&gt;23.5%&lt;/a&gt;.
 Some engineering teams now spend a significant portion of their week 
cleaning up “AI slop” delivered by design teams who skipped a rigorous 
review process.&lt;/li&gt;&lt;li&gt;&lt;b&gt;The communication gap&lt;/b&gt;&lt;br /&gt;Only &lt;a href="https://www.lyssna.com/blog/ux-design-trends/"&gt;69% of designers&lt;/a&gt; feel AI improves the quality of their work, compared to &lt;b&gt;82% of developers&lt;/b&gt;. This gap exists because “code that compiles” is not the same as “code that is maintainable.”&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;When
 a designer hands off AI-generated code that ignores a company’s 
internal naming conventions or management patterns, they aren’t helping 
the engineer; they are creating a puzzle that someone else has to solve 
later.&lt;/p&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://files.smashing.media/articles/ux-designer-nightmare-production-ready-becomes-design-deliverable/3-issues-developers-face-ai-generated-code.jpg"&gt;&lt;img alt="Typical issues that developers face with AI-generated code" height="600" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ux-designer-nightmare-production-ready-becomes-design-deliverable/3-issues-developers-face-ai-generated-code.jpg" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;Typical issues that developers face with AI-generated code. (Image source: &lt;a href="https://www.netcorpsoftwaredevelopment.com/blog/ai-generated-code-statistics"&gt;Netcorp&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;h3 id="the-solution"&gt;The Solution&lt;/h3&gt;&lt;p&gt;We need to move away from the nightmare of the “&lt;b&gt;Solo Full-Stack Designer&lt;/b&gt;” and toward a model of &lt;b&gt;designer/coder collaboration&lt;/b&gt;.&lt;/p&gt;&lt;p&gt;&lt;b&gt;The ideal reality:&lt;/b&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;The Partnership&lt;/b&gt;&lt;br /&gt;Instead of designers trying to be mediocre coders, they should work in a &lt;b&gt;human-AI-human loop&lt;/b&gt;. A senior UX designer should work &lt;i&gt;with&lt;/i&gt; an engineer to use AI; the designer creates prompts for &lt;b&gt;intent, accessibility, and user flow&lt;/b&gt;, while the engineer creates prompts for &lt;b&gt;architecture and performance&lt;/b&gt;.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Design systems as guardrails&lt;/b&gt;&lt;br /&gt;To prevent accessibility debt from spreading at scale, &lt;a href="https://webaim.org/projects/million/"&gt;accessible components must be the default&lt;/a&gt;
 in your design system. AI should be used to feed these tokens into your
 UI, ensuring that even generated code stays within the “source of 
truth.”&lt;/li&gt;&lt;/ul&gt;&lt;h2 id="beyond-the-prompt"&gt;Beyond The Prompt&lt;/h2&gt;&lt;div aria-hidden="true" class="c-friskies-box partners partners__lead partners__lead-place partners__external" data-amount="1" data-audience="non-subscriber" data-remove="true" data-rendered="true"&gt;&lt;ul&gt;&lt;a class="partners__native--smashing" href="https://www.smashingmagazine.com/contact/"&gt;
        &lt;picture&gt;
          &lt;source media="(max-width: 600px)"&gt;&lt;/source&gt;
          &lt;img alt="Advertise with Smashing Magazine" width="325" /&gt;
        &lt;/picture&gt;
      &lt;/a&gt;&lt;/ul&gt;&lt;/div&gt;&lt;p&gt;The industry is currently in a state of “AI Infatuation,” but the pendulum will eventually swing back toward quality.&lt;/p&gt;&lt;blockquote class="pull-quote"&gt;&lt;p&gt;&lt;a aria-label="Share on Twitter" class="pull-quote__link" href="https://twitter.com/share?text=%0aThe%20UX%20designer%e2%80%99s%20nightmare%20ends%20when%20we%20stop%20trying%20to%20compete%20with%20AI%20tools%20at%20what%20they%20do%20best%20%28generating%20syntax%29%20and%20keep%20our%20focus%20on%20what%20they%20cannot%20do%20%28understanding%20human%20complexity%29.%0a&amp;amp;url=https://smashingmagazine.com%2f2026%2f04%2fproduction-ready-becomes-design-deliverable-ux%2f"&gt;The
 UX designer’s nightmare ends when we stop trying to compete with AI 
tools at what they do best (generating syntax) and keep our focus on 
what they cannot do (understanding human complexity).&lt;/a&gt;&lt;/p&gt;&lt;div class="pull-quote__quotation"&gt;&lt;div class="pull-quote__bg"&gt;&lt;span class="pull-quote__symbol"&gt;“&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;p&gt;Businesses
 that prioritise “designer-shipped code” without engineering oversight 
will eventually face a reckoning of technical debt, security breaches, 
and accessibility lawsuits. The designers who thrive in 2026 and beyond 
will be those who refuse to be “prompt operators” and instead position 
themselves as the &lt;b&gt;guardians of the user experience&lt;/b&gt;. This is the perfect outcome for experienced designers and for the industry.&lt;/p&gt;&lt;p&gt;Our
 value has always been our ability to advocate for the human on the 
other side of the screen. We must use AI to augment our design thinking,
 allowing us to test more ideas and iterate faster, but we must never 
let it replace the specialised engineering expertise that ensures our 
designs technically &lt;i&gt;work&lt;/i&gt; for everyone.&lt;/p&gt;&lt;h3 id="summary-checklist-for-ux-designers"&gt;Summary Checklist for UX Designers&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Work Together.&lt;/b&gt;&lt;br /&gt;Use
 AI-made code as a starting point to talk with your developers. Don’t 
use it as a shortcut to avoid working with them. Ask them to help you 
with prompts for code creation for the best outcomes.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Understand the “Why”.&lt;/b&gt;&lt;br /&gt;Never submit code you don’t understand. If you can’t explain how the AI-generated logic works, don’t include it in your work.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Build for Everyone.&lt;/b&gt;&lt;br /&gt;Good
 design is more than just looks. Use AI to check if your code works for 
people using screen readers or keyboards, not just to make things look 
pretty.&lt;/li&gt;&lt;/ul&gt;</description><link>http://honeyvig.blogspot.com/2026/04/the-ux-designers-nightmare-when.html</link><author>noreply@blogger.com (H)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-9165069509664255576.post-2450539452636518949</guid><pubDate>Mon, 13 Apr 2026 12:48:00 +0000</pubDate><atom:updated>2026-04-13T05:48:33.349-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Career</category><category domain="http://www.blogger.com/atom/ns#">mission</category><category domain="http://www.blogger.com/atom/ns#">UI</category><category domain="http://www.blogger.com/atom/ns#">UX</category><category domain="http://www.blogger.com/atom/ns#">vision</category><title> What Will Engineers Actually Do in 2030? </title><description>&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h2 class="ember-view reader-text-block__heading-2" id="ember61"&gt;
      &#128293; Big Story of the Week
    &lt;/h2&gt;

  






            
        
    &lt;h3 class="ember-view reader-text-block__heading-3" id="ember62"&gt;
      &#129489;&#128187; The Engineer of 2030: Builder, Reviewer, or AI Trainer?
    &lt;/h3&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember63"&gt;
      If you look at how you work today… and compare it to even a year ago, something feels different.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember64"&gt;
      You’re still coding. But not in the same way.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember65"&gt;
      Sometimes, it feels like:
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember66"&gt;
            &lt;/p&gt;&lt;ul&gt;&lt;li&gt;You’re reviewing more than writing&lt;/li&gt;&lt;li&gt;Thinking more than typing&lt;/li&gt;&lt;li&gt;Guiding more than building&lt;/li&gt;&lt;/ul&gt;

    &lt;p&gt;&lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember67"&gt;
      And that raises an uncomfortable but important question:
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember68"&gt;
      &#128073;&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;em&gt;What does it actually mean to be an engineer in the future?&lt;/em&gt;
    &lt;/p&gt;

  










            
  &lt;hr class="reader-divider-block__horizontal-rule" /&gt;



            
        
    &lt;h3 class="ember-view reader-text-block__heading-3" id="ember69"&gt;
      &#129504; The Shift Has Already Started
    &lt;/h3&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember70"&gt;
      Let’s be real.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember71"&gt;
      AI can now:
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember72"&gt;
            &lt;/p&gt;&lt;ul&gt;&lt;li&gt;Generate full functions in seconds&lt;/li&gt;&lt;li&gt;Suggest optimizations&lt;/li&gt;&lt;li&gt;Write tests you might skip&lt;/li&gt;&lt;li&gt;Even explain your own code back to you&lt;/li&gt;&lt;/ul&gt;

    &lt;p&gt;&lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember73"&gt;
      So naturally, your role starts to shift.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember74"&gt;
      Not overnight. But quietly, consistently.
    &lt;/p&gt;

  










            
  &lt;hr class="reader-divider-block__horizontal-rule" /&gt;



            
        
    &lt;h3 class="ember-view reader-text-block__heading-3" id="ember75"&gt;
      ⚙️ So… What Are We Becoming?
    &lt;/h3&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember76"&gt;
      The future engineer isn’t just one thing anymore.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember77"&gt;
      It’s a mix of roles.
    &lt;/p&gt;

  










            
  &lt;hr class="reader-divider-block__horizontal-rule" /&gt;



            
        
    &lt;h3 class="ember-view reader-text-block__heading-3" id="ember78"&gt;
      &#128313; 1. The Builder (Still Important)
    &lt;/h3&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember79"&gt;
      Yes — coding isn’t going away.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember80"&gt;
      You still need to:
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember81"&gt;
            &lt;/p&gt;&lt;ul&gt;&lt;li&gt;Understand systems&lt;/li&gt;&lt;li&gt;Write critical logic&lt;/li&gt;&lt;li&gt;Handle edge cases&lt;/li&gt;&lt;/ul&gt;

    &lt;p&gt;&lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember82"&gt;
      Because AI is fast… but it doesn’t&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;em&gt;understand context like you do.&lt;/em&gt;
    &lt;/p&gt;

  










            
  &lt;hr class="reader-divider-block__horizontal-rule" /&gt;



            
        
    &lt;h3 class="ember-view reader-text-block__heading-3" id="ember83"&gt;
      &#128313; 2. The Reviewer (More Important Than Ever)
    &lt;/h3&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember84"&gt;
      AI can generate code.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember85"&gt;
      But can it guarantee:
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember86"&gt;
            &lt;/p&gt;&lt;ul&gt;&lt;li&gt;Business correctness? ❌&lt;/li&gt;&lt;li&gt;Edge case handling? ❌&lt;/li&gt;&lt;li&gt;Long-term maintainability? ❌&lt;/li&gt;&lt;/ul&gt;

    &lt;p&gt;&lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember87"&gt;
      That’s where you come in.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember88"&gt;
      You’re no longer just writing code — &#128073; you’re&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;strong&gt;validating intelligence&lt;/strong&gt;.
    &lt;/p&gt;

  










            
  &lt;hr class="reader-divider-block__horizontal-rule" /&gt;



            
        
    &lt;h3 class="ember-view reader-text-block__heading-3" id="ember89"&gt;
      &#128313; 3. The AI Trainer (The New Role)
    &lt;/h3&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember90"&gt;
      This is where things get interesting.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember91"&gt;
      You’re now:
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember92"&gt;
            &lt;/p&gt;&lt;ul&gt;&lt;li&gt;Writing better prompts&lt;/li&gt;&lt;li&gt;Refining outputs&lt;/li&gt;&lt;li&gt;Teaching AI what “good” looks like&lt;/li&gt;&lt;/ul&gt;

    &lt;p&gt;&lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember93"&gt;
      In a way… &#128073; you’re training a junior developer that learns instantly.
    &lt;/p&gt;

  










            
  &lt;hr class="reader-divider-block__horizontal-rule" /&gt;



            
        
    &lt;h3 class="ember-view reader-text-block__heading-3" id="ember94"&gt;
      ⚠️ The Risk Nobody Talks About
    &lt;/h3&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember95"&gt;
      There’s a hidden danger in all this.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember96"&gt;
      If we rely too much on AI:
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember97"&gt;
            &lt;/p&gt;&lt;ul&gt;&lt;li&gt;Our fundamentals may weaken&lt;/li&gt;&lt;li&gt;Our debugging instincts may slow down&lt;/li&gt;&lt;li&gt;Our deep understanding may fade&lt;/li&gt;&lt;/ul&gt;

    &lt;p&gt;&lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember98"&gt;
      And that’s risky.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember99"&gt;
      Because when AI fails — &#128073;&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;em&gt;you’re still the final line of defense.&lt;/em&gt;
    &lt;/p&gt;

  










            
  &lt;hr class="reader-divider-block__horizontal-rule" /&gt;



            
        
    &lt;h3 class="ember-view reader-text-block__heading-3" id="ember100"&gt;
      &#127757; The Bigger Reality
    &lt;/h3&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember101"&gt;
      The barrier to building software is dropping fast.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember102"&gt;
      Which means:
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember103"&gt;
            &lt;/p&gt;&lt;ul&gt;&lt;li&gt;More builders are entering the space&lt;/li&gt;&lt;li&gt;More products are being created&lt;/li&gt;&lt;li&gt;More competition is coming&lt;/li&gt;&lt;/ul&gt;

    &lt;p&gt;&lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember104"&gt;
      So the real differentiator won’t be: ❌ Who can code ✅ But who can&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;strong&gt;think, design, and adapt&lt;/strong&gt;
    &lt;/p&gt;

  










            
  &lt;hr class="reader-divider-block__horizontal-rule" /&gt;



            
        
    &lt;h3 class="ember-view reader-text-block__heading-3" id="ember105"&gt;
      &#128302; What the Best Engineers Will Do
    &lt;/h3&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember106"&gt;
      The engineers who thrive won’t fight AI.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember107"&gt;
      They’ll:
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember108"&gt;
            &lt;/p&gt;&lt;ul&gt;&lt;li&gt;Use it to move faster&lt;/li&gt;&lt;li&gt;Focus on deeper problems&lt;/li&gt;&lt;li&gt;Build better systems, not just more code&lt;/li&gt;&lt;/ul&gt;

    &lt;p&gt;&lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember109"&gt;
      Because the game is changing from: &#128073;&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;em&gt;“Write more code”&lt;/em&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;to &#128073;&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;em&gt;“Create more impact”&lt;/em&gt;
    &lt;/p&gt;

  










            
  &lt;hr class="reader-divider-block__horizontal-rule" /&gt;



            
        
    &lt;h3 class="ember-view reader-text-block__heading-3" id="ember110"&gt;
      &#128161; Engineer’s Takeaway
    &lt;/h3&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember111"&gt;
      The future engineer is not just a builder.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember112"&gt;
      They are: &#129504; A thinker &#128269; A reviewer &#129302; A guide to AI
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember113"&gt;
      And maybe that’s the real evolution.
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember114"&gt;
      Because in the end, &#128073;&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;strong&gt;tools will change — but great thinking never goes out of style.&lt;/strong&gt;
    &lt;/p&gt;

  










            
  &lt;hr class="reader-divider-block__horizontal-rule" /&gt;



            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember115"&gt;
      ✍️&lt;span class="white-space-pre"&gt; &lt;/span&gt;&lt;em&gt;EngiSphere Insight:&lt;/em&gt;&lt;span class="white-space-pre"&gt; &lt;/span&gt;“The engineers who win in the AI era won’t be the fastest coders — they’ll be the smartest decision-makers.”
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember116"&gt;
      #SoftwareEngineering #AI #FutureOfWork #Developers #TechTrends #EngiSphere
    &lt;/p&gt;

  






            
        
    &lt;p class="ember-view reader-text-block__paragraph" id="ember117"&gt;
      #ArtificialIntelligence #Programming #CareerGrowth #TechLeadership #Innovation
    &lt;/p&gt;</description><link>http://honeyvig.blogspot.com/2026/04/what-will-engineers-actually-do-in-2030.html</link><author>noreply@blogger.com (H)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-9165069509664255576.post-8223300613439298879</guid><pubDate>Mon, 06 Apr 2026 13:55:00 +0000</pubDate><atom:updated>2026-04-06T06:55:37.874-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Accessibility</category><category domain="http://www.blogger.com/atom/ns#">Figma</category><category domain="http://www.blogger.com/atom/ns#">Tools</category><title>Testing Font Scaling For Accessibility With Figma Variables</title><description>&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="c-garfield-summary"&gt;&lt;section aria-label="Quick summary" class="article__summary"&gt;Accessibility
 works best when it blends into everyday design workflows. The goal 
isn’t a big transformation, but simple work processes that fit naturally
 into a team’s routine. With Figma variables, testing font size 
increases becomes part of the design flow itself, making accessibility 
feel almost inevitable rather than optional.&lt;/section&gt;&lt;/div&gt;&lt;p&gt;Building a
 true culture of digital accessibility in a company is a mission of 
resilience and perseverance. It’s not difficult for the discourse on 
accessibility to fall into the usual clichés. Accessibility is very 
important for people. The accessibility of digital products and services
 promotes inclusion. Or even, all professionals on the teams should be 
involved in accessibility work. Of course. No one in their right mind 
will dispute any of these statements (I hope).&lt;/p&gt;&lt;p&gt;However, the second part of this conversation, which very few companies reach, is &lt;em&gt;“how?”&lt;/em&gt;
 How do we make this happen in the midst of the day-to-day work of 
digital transformation teams, which, as we all know, are immersed in 
demanding scripts, often with a very limited number of people available?
 Most of the time, the choice ends up being between &lt;em&gt;“we do this”&lt;/em&gt; and &lt;em&gt;“that.”&lt;/em&gt; And it shouldn’t, because, in these cases, I never saw accessibility winning in this equation.&lt;/p&gt;&lt;p&gt;It
 shouldn’t be this way. You don’t need to be this way. First of all, 
because choosing between accessibility and anything else isn’t the right
 choice. Accessibility is no longer just another feature to be added to 
the others. It’s an added value for the business and, currently, a legal
 obligation that can have serious consequences for companies. On the 
other hand, there are intelligent, optimized, and impactful ways to 
incorporate accessibility principles into the natural dynamics of teams.
 It’s possible to work on accessibility without turning team operations 
upside down. In essence, that’s what AccessibilityOps does. &lt;strong&gt;Empowering people&lt;/strong&gt; and &lt;strong&gt;providing teams with simple processes&lt;/strong&gt; so they can &lt;strong&gt;integrate accessibility work into their daily routines&lt;/strong&gt; without disproportionate effort.&lt;/p&gt;&lt;h2 id="accessibility-and-design"&gt;Accessibility And Design&lt;/h2&gt;&lt;p&gt;Working
 on digital accessibility in design can involve several actions. It’s 
clear that we need to pay particular attention to color and how it’s 
used to convey meaning. Of course, the interaction sizes of elements 
must be comfortable. But, most importantly, we must &lt;strong&gt;think about design from a versatile perspective&lt;/strong&gt;.
 An interface isn’t a poster. We can control many aspects of that 
design, but how users interact with the interface is subject to an 
endless number of variables. The type of device, context, purpose, 
network quality, etc. All of this greatly affects each person’s 
experience and interaction. Along with all this, when digital 
accessibility concerns are brought into the design process, it adds even
 more variables.&lt;/p&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/01-assistive-technologies.png"&gt;&lt;img alt="Assistive technologies" height="533" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/01-assistive-technologies.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;(&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/01-assistive-technologies.png"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;People often use what are called &lt;strong&gt;assistive technologies and strategies&lt;/strong&gt;.
 Basically, these are technological tools or, at the very least, 
“tricks” that people resort to in order to find more comfortable usage 
models. The famous screen readers, commonly associated with the use of 
blind people (but which are not only useful to them), for example, are 
an assistive technology. Changing colors or color contrasts between 
different elements is also an assistive technology. Increasing the font 
size (which we discussed in this text) is another example. There are 
countless assistive technologies and strategies. Almost as many as the 
different contexts of use for each person.\&lt;/p&gt;&lt;div class="feature-panel-container" data-audience="non-subscriber" data-remove="true"&gt;&lt;aside class="feature-panel"&gt;&lt;div class="feature-panel-right-col"&gt;&lt;p&gt;&lt;/p&gt;&lt;/div&gt;&lt;/aside&gt;&lt;/div&gt;&lt;h2 id="we-don-t-control-everything"&gt;We Don’t Control Everything&amp;nbsp;&lt;/h2&gt;&lt;p&gt;In
 other words (and this is the “bad news” for us designers), “our design”
 is subject, from the users’ perspective, to transformations that we 
don’t control. It will be “transformed” by the user, ensuring that they 
can interact with the application and everything it offers in the most 
comfortable way possible. And that’s a good thing. If this happens and 
everything goes well, we will have surely done our accessibility work 
very well, and we all deserve congratulations. If the user applies any 
of these support technologies and strategies and still cannot use the 
digital application, it’s a sign that something is not working as it 
should.&lt;/p&gt;&lt;p&gt;Oh, and speaking of which. Don’t even think about blocking
 the use of these technologies or support strategies. They may be 
“destroying” your beautiful design, but they are allowing more and more 
people to actually use the app. In the end, wasn’t that exactly what we 
promised we wanted to do? Design for (all) people. Without exception?&lt;/p&gt;&lt;h2 id="increase-font-size"&gt;Increase Font Size&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/03/testing-font-scaling-accessibility-figma-variables/#increase-font-size"&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;How
 many times have we heard someone — friends, family, or even colleagues —
 complaining that this or that text is too small? Text plays a very 
important role in the digital experience. Much information is conveyed 
through text: instructions for use, button captions, or interactive 
elements. All of this uses text as a communication tool. If reading all 
these elements is difficult, naturally, the experience is severely 
impaired.&lt;/p&gt;&lt;p&gt;Comfortable text reading, regardless of its function, is
 a non-negotiable principle. This reading can be facilitated by using 
comfortable sizes in the design. However, supporting technologies and 
strategies, through the functionality of increasing font size, can also 
help improve readability. According to &lt;a href="https://appt.org/en/stats/font-size"&gt;APPT&lt;/a&gt; data, &lt;strong&gt;26% of Android and iOS mobile device users&lt;/strong&gt;
 increase the default font size (data from February 2026). One in four 
users increases the font size on their smartphone. This is a very 
significant sample of people, making this functionality unavoidable in 
design processes.&lt;/p&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/02-chart.png"&gt;&lt;img alt="Chart with font sizes where 26% of users use large font-size." height="533" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/02-chart.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;(&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/02-chart.png"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;h2 id="compliance-with-guidelines"&gt;Compliance With Guidelines&lt;/h2&gt;&lt;p&gt;Increasing
 font size in interfaces can represent a huge design challenge. It’s 
important to understand that, suddenly, some text elements, due to user 
actions, can double in size from their initial size.&lt;/p&gt;&lt;blockquote&gt;“With
 the exception of captions and text images, text can be resized without 
assistive technology up to 200% without loss of content or 
functionality.”&lt;br /&gt;&lt;br /&gt;— &lt;a href="https://acessibilidade.gov.pt/wcag/#resize-text"&gt;Success criterion 1.4.4, “Resizing Text”&lt;/a&gt; of the Web Content Accessibility Guidelines (WCAG), version 2.2&lt;/blockquote&gt;&lt;p&gt;This
 success criterion is at the AA compliance level, meaning this is an 
absolutely mandatory feature according to any legal framework.&lt;/p&gt;&lt;p&gt;It’s
 easy to understand the 200% in this success criterion. If we assume we 
design the interfaces at a 100% scale, meaning the element size is the 
initial size, then increasing the text by up to 200% will correspond to 
doubling the initial size. Other enlargement scales can also be used, 
such as 120%, 140%, and so on. In other words, we have to ensure that 
users can increase the text to double its initial size through 
supporting technologies or strategies (and this is not a minor detail).&lt;/p&gt;&lt;p&gt;To
 comply with this standard, we don’t need to provide text size increase 
tools in the interfaces. In practice, these features are nothing more 
than redundancy. Devices already allow this to be done in a standardized
 way. Users who really need this setting know it (because, without it, 
their lives would be much more difficult). Well, they already have this 
setting applied across their device. And that means we can eliminate 
these additional interface elements, simplifying the experience.&lt;/p&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/03-feature.png"&gt;&lt;img alt="Text size increase tool in the interface" height="533" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/03-feature.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;(&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/03-feature.png"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;h2 id="standardized-access"&gt;Standardized Access&lt;/h2&gt;&lt;p&gt;An
 important concept to remember about assistive technologies, 
particularly in this case regarding increasing font size, is that most 
devices already have many of these tools installed by default. In other 
words, in many cases, users don’t need to purchase their own software or
 buy a specific type of device just to have this functionality.&lt;/p&gt;&lt;p&gt;Whether
 on mobile devices or even in web browsers, in the vast majority of 
cases, it’s easy to find installed features that allow you to increase 
the default font size we’re using throughout the interface. This 
principle of increasing font size can be applied to digital products, 
such as apps, or even to any type of website running on the standard web
 browsers used today.&lt;/p&gt;&lt;h3 id="iphones"&gt;iPhones&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/03/testing-font-scaling-accessibility-figma-variables/#iphones"&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;On
 iPhone devices, the font size increase feature is integrated by 
default. To use this feature, simply access the “Settings” panel, select
 “Accessibility,” and within the “Vision” options group, access the 
“Text Size and Display” feature and configure the desired font size 
increase on that screen.&lt;/p&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/04-iphones.png"&gt;&lt;img alt="iPhone screens with settings on accessibility" height="533" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/04-iphones.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;(&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/04-iphones.png"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;h3 id="google-chrome"&gt;Google Chrome&lt;/h3&gt;&lt;p&gt;Web
 browsers also offer, by default, the functionality to increase font 
size. For example, in Google Chrome, this feature is available in the 
“Options” panel, specifically in the “Appearance” area. In the list of 
options that appear in this group, simply select the “Font size” option.
 Normally, the “Medium — Recommended” option will be selected. You can 
change this setting to any other available font size. Try, for example, 
the “Very large” option.&lt;/p&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/05-google-chrome.png"&gt;&lt;img alt="Google Chrome settings on accessibility" height="533" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/05-google-chrome.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;(&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/05-google-chrome.png"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;h2 id="test-in-figma"&gt;Test In Figma&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/03/testing-font-scaling-accessibility-figma-variables/#test-in-figma"&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;To ensure that digital accessibility work becomes effective in the daily lives of teams, it is essential to find &lt;strong&gt;simple work processes&lt;/strong&gt;.
 Actions or initiatives that can be integrated into the team’s routine, 
that address accessibility in an integrated way, and do not require a 
dramatic transformation of the current reality. If that were necessary, 
he believes, it wouldn’t happen most of the time. Therefore, designing 
simple work processes is half the battle for accessibility to truly 
happen, in this case, also within a design team.&lt;/p&gt;&lt;p&gt;Regarding testing
 font size increases in design, we have extraordinary tools at our 
disposal today. Those who remember the days of designing complex 
interfaces in &lt;a href="https://www.adobe.com/pt/products/photoshop.html"&gt;Adobe Photoshop&lt;/a&gt; will recognize the differences in the tools we have today (and thankfully so). It’s now possible, through tools like &lt;a href="https://www.figma.com/design/"&gt;Figma&lt;/a&gt;, to create such dynamism in design that testing font size increases for accessibility becomes almost unavoidable for the team.&lt;/p&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/06-hands-on.png"&gt;&lt;img alt="Visualization on font sizes" height="533" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/06-hands-on.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;(&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/06-hands-on.png"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: To take this test, you need to have a strong grasp of Figma’s &lt;a href="https://help.figma.com/hc/en-us/articles/360039957034-Create-and-apply-text-styles"&gt;text styles&lt;/a&gt;, &lt;a href="https://help.figma.com/hc/en-us/articles/360040451373-Guide-to-auto-layout"&gt;auto layouts&lt;/a&gt;, and &lt;a href="https://help.figma.com/hc/en-us/articles/15339657135383-Guide-to-variables-in-Figma"&gt;variables&lt;/a&gt;.
 These three are fundamental tools for success without much extra 
effort. If you haven’t yet mastered these features, it’s highly 
recommended that you start there. Don’t skip steps. Learning is a 
gradual process that must be followed in a structured, step-by-step 
manner.&lt;/p&gt;&lt;h3 id="where-do-we-want-to-go"&gt;Where Do We Want To Go?&lt;/h3&gt;&lt;p&gt;The
 font size increase test in Figma that we want to perform is simple. We 
want to have a set of variables available for all the text styles we use
 in the interface, allowing us to choose whether we want to see the 
interface with the text at a scale of 100%, 120%, 140%, 160%, 180%, or 
200%. As we apply this set of variables (much like applying variables 
for light and dark mode), we observe the transformations of the text in 
the interface and understand to what extent adaptations are needed in 
each version of the interface with different typographic scales.&lt;/p&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/07-font-scaling.png"&gt;&lt;img alt="Font scaling" height="533" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/07-font-scaling.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;(&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/07-font-scaling.png"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;h3 id="how-do-we-make-this-happen"&gt;How Do We Make This Happen?&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/03/testing-font-scaling-accessibility-figma-variables/#how-do-we-make-this-happen"&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;For this test to go so smoothly, you need to do some groundwork. &lt;a href="https://dxd.pt/design-systems/"&gt;Design systems&lt;/a&gt;
 can greatly help optimize much of this initial work. But I won’t lie to
 you. For the test to work well, your design needs to have a very 
serious level of organization and systematization.&lt;/p&gt;&lt;p&gt;This isn’t 
really a guide, because each team will have its own work model, and 
these recommendations can be applied in different ways (and that’s 
okay). However, for this test to work, it’s important to ensure certain 
assumptions in the design. To help you phase the implementation of this 
test model, here are some steps to follow. Step-by-step instructions to 
guide you in organizing your files and ensuring you can fully execute 
this test in the simplest and most practical way possible.&lt;/p&gt;&lt;h3 id="1-designing-the-interfaces"&gt;1. Designing The Interfaces&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/03/testing-font-scaling-accessibility-figma-variables/#1-designing-the-interfaces"&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;It
 all starts with the design. Before any testing, the focus should, as it
 should, be on the design of each interface that we will want to test 
later. At this stage, there is still no specific concern with the font 
size increase test that we will perform later. Naturally, all interface 
design should, from the outset, follow the most basic &lt;a href="https://www.a11yproject.com/checklist/"&gt;accessibility recommendations&lt;/a&gt; applied to design.&lt;/p&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/08-design-screens.png"&gt;&lt;img alt="Design screens" height="533" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/08-design-screens.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;(&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/08-design-screens.png"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;h3 id="2-apply-auto-layouts-to-all-elements"&gt;2. Apply Auto Layouts To All Elements&amp;nbsp;&lt;/h3&gt;&lt;p&gt;In
 every screen design you create, you’ll need to ensure you apply auto 
layouts perfectly. This is a very important step. It’s this consistent 
application of auto layouts to the entire structure and design elements 
that will later guarantee the scalability of the interface when we start
 testing font size increases. You really can’t underestimate this step. 
If you don’t pay it the attention it deserves, you’ll see when we test 
typographic scaling in the interfaces, everything breaking down like an 
elephant in a china shop.&lt;/p&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/09-auto-layout.png"&gt;&lt;img alt="Auto layout" height="534" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/09-auto-layout.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;(&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/09-auto-layout.png"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;h3 id="3-structuring-and-applying-text-styles"&gt;3. Structuring And Applying Text Styles&lt;/h3&gt;&lt;p&gt;To
 perform our font size increase test, we’ll also need you to have 
applied text styles to each interface design. You probably even started 
creating them as you were drawing. Great. If you haven’t done so, it’s 
important that you do it now. For the test to work perfectly, we really 
need this. Don’t leave any text element in the design without a text 
style applied.&lt;/p&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/10-text-styles.png"&gt;&lt;img alt="Text styles" height="533" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/10-text-styles.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;(&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/10-text-styles.png"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;h3 id="4-define-the-set-of-variables-100"&gt;4. Define The Set Of Variables 100%&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/03/testing-font-scaling-accessibility-figma-variables/#4-define-the-set-of-variables-100"&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;This
 test forces a fairly high degree of optimization. In practice, this 
means we will have to use Figma variables for all the characteristics of
 the text styles we have in the interface. At this stage, you must 
define Figma “number” variables for at least the font-size and 
line-height of the text styles you applied to the drawing. With this 
step, you are defining the font size increase scale values for a 100% 
visualization model, that is, the initial and reference version of the 
drawing. It is important that you structure these variables for each 
text style in the drawing because, subsequently, we will have to 
consider the enlargement scale of each of these text elements.&lt;/p&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/11-variables-100-percent.png"&gt;&lt;img alt="Defining the set of variables 100%" height="533" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/11-variables-100-percent.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;(&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/11-variables-100-percent.png"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;h3 id="5-apply-the-variables-to-the-text-styles"&gt;5. Apply The Variables To The Text Styles&amp;nbsp;&lt;/h3&gt;&lt;p&gt;Having
 defined the variables for the 100% scale text styles, you must now 
apply them to the elements of the text styles already created. Don’t 
forget to apply variables at least to the font-size and line-height 
characteristics. If you have more typographical variables, that’s fine. 
But you should at least have variables applied to font-size and 
line-height. This is really very important.&lt;/p&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/12-text-styles-variables.png"&gt;&lt;img alt="Applying variables to the text styles" height="533" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/12-text-styles-variables.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;(&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/12-text-styles-variables.png"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;h3 id="6-define-the-variables-for-increasing-the-text-size"&gt;6. Define The Variables For Increasing The Text Size&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/03/testing-font-scaling-accessibility-figma-variables/#6-define-the-variables-for-increasing-the-text-size"&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Now
 that you have the variables applied to the 100% scale text styles, the 
next step is to create the variables for the other font size increase 
scales. In practice, you have to create the variables that will tell the
 system what font size each text style will grow to when the increase 
scale is 120%, 140%, 160%, etc.&lt;/p&gt;&lt;p&gt;To define the font-size and 
line-height values, simply multiply the initial value by the scale 
percentage. For example, if a text style has a font-size of 16px, the 
size for the 120% scale will be 16 multiplied by 1.2, which gives a 
result of 19.2. Repeat this calculation for all font-size and 
line-height values of the font size increase scale percentages you 
choose.&lt;/p&gt;&lt;p&gt;You can also choose whether or not to apply rounding to 
the final values. This is an approximate test, and therefore any 
differences that may arise from rounding will not affect the final 
perception of the test result.&lt;/p&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/13-font-scaling-variables.png"&gt;&lt;img alt="Font scalling variables" height="533" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/13-font-scaling-variables.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;(&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/13-font-scaling-variables.png"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;h3 id="7-apply-variables-to-different-scale-versions"&gt;7. Apply Variables To Different Scale Versions&lt;/h3&gt;&lt;p&gt;The
 moment of truth has arrived. The next step is to understand if we have 
everything working so that the test runs perfectly. Therefore, you 
should copy the original interface and apply the set of variables for 
each of the font size increase rates that make sense to you. Repeat this
 process for all the font size increase percentages you have defined.&lt;/p&gt;&lt;p&gt;As
 a suggestion, you can use the 120%, 140%, 160%, 180%, and 200% increase
 percentages as a reference. If you want to simplify, you can reduce the
 number of scaling percentages you are working with. Regardless of the 
number of percentages you are working with, you should always work with 
the minimum of 100% and 200% scales.&lt;/p&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/14-apply-different-scales.png"&gt;&lt;img alt="Applied variables to different scale versions" height="533" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/14-apply-different-scales.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;(&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/14-apply-different-scales.png"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;h3 id="8-identify-areas-for-improvement"&gt;8. Identify Areas For Improvement&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/03/testing-font-scaling-accessibility-figma-variables/#8-identify-areas-for-improvement"&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;By
 applying different font size increase scales to the same screen, it’s 
easy to understand where improvements might be needed. This is where the
 real test of increasing font size in interface design and the most 
interesting accessibility work begins.&lt;/p&gt;&lt;p&gt;In your analysis of the various screens, keep some important aspects in mind:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The
 fact that the text appears gigantic isn’t a problem and doesn’t “ruin” 
the design. Remember that this can mean the difference between someone 
being able to use a particular product or service or not.&lt;/li&gt;&lt;li&gt;An 
accessibility problem exists when increasing the font size makes it 
impossible for the user to read certain texts or to activate certain 
controls.&lt;/li&gt;&lt;li&gt;For text elements that are already very large, 
increasing the font size might not make sense. Doing so could make those
 elements disproportionate, which wouldn’t improve readability (since 
they are already a good size) and would occupy completely unnecessary 
space.&lt;/li&gt;&lt;li&gt;If there are elements that appear to be popping out of the screen, the first step is to confirm how you are applying &lt;strong&gt;auto layout&lt;/strong&gt;. Many design aspects can be easily resolved with the proper use of auto layout.&lt;/li&gt;&lt;li&gt;Regardless of the scale of font size increase, it is essential to maintain the &lt;strong&gt;visual hierarchy of the typography&lt;/strong&gt;, as this readability is important for perceiving the different levels of information present on the screen.&lt;/li&gt;&lt;li&gt;This
 test can help identify elements that may need adjustments directly in 
the code to function well at a given scale of increase. Not everything 
can be solved through design alone, and that’s perfectly fine. 
Accessibility is essentially a team effort.&lt;/li&gt;&lt;/ul&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/15-critical-points.png"&gt;&lt;img alt="Critical points for improvement" height="533" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/15-critical-points.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;(&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/15-critical-points.png"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;h3 id="9-make-corrections-and-adjustments-to-the-design"&gt;9. Make Corrections And Adjustments To The Design&lt;/h3&gt;&lt;p&gt;Finally,
 based on the various screens with different text enlargement scales 
applied, you can make the design changes that make sense. Some of these 
adjustments may only be necessary in code. In these cases, you document 
all these suggestions and pass them on to the development team. It is 
also crucial to reinforce (again) that some of the problems you may 
encounter in the design can be quickly resolved in the design process, 
with the simple and correct application of auto-layout properties.&lt;/p&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/16-make-changes.png"&gt;&lt;img alt="Design changes to those critical points" height="533" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/16-make-changes.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;(&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/16-make-changes.png"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;h3 id="10-go-back-to-the-beginning-and-repeat-the-process"&gt;10. Go Back To The Beginning And Repeat The Process&lt;/h3&gt;&lt;p&gt;This
 is a cyclical approach. This means you should repeat these steps, or 
variations thereof, as many times as necessary throughout the project. 
It’s natural that, over time and with process optimization, some of 
these steps will cease to make sense. That’s absolutely not a problem. 
But the most important thing to realize here is that accessibility and 
this process of testing font size increases shouldn’t be done just once,
 and that’s it. It’s a test to be done many, many times throughout the 
day-to-day work of each project and team.&lt;/p&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/17-staring-point.png"&gt;&lt;img alt="Starting point" height="533" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/17-staring-point.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;(&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/17-staring-point.png"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;h2 id="the-role-of-design-systems"&gt;The Role Of Design Systems&amp;nbsp;&lt;a class="anchor" href="https://www.smashingmagazine.com/2026/03/testing-font-scaling-accessibility-figma-variables/#the-role-of-design-systems"&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;At
 first glance, this list of steps might seem like a complex exercise. 
But it’s not. This is because the vast majority, if not all, of these 
steps are easy to execute in any context where a design system exists. 
In fact, design systems have become an &lt;strong&gt;unavoidable standard&lt;/strong&gt;
 in the Product Design industry. We can discuss what each team calls a 
design system, but the truth is that it’s very difficult today to find a
 Product Design team that doesn’t have, at the very least, a minimally 
structured library of components and styles.&lt;/p&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/18-design-systems.png"&gt;&lt;img alt="Visualization on design systems" height="533" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/18-design-systems.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;&lt;br /&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;With
 this foundation, whether more or less documented, it’s very easy to 
apply this type of font size increase test using Figma variables. 
Furthermore, if your design system already has, for example, structured 
variables for light and dark mode, it means you’re already applying the 
exact same principles we used to perform this test. So, nothing new.&lt;/p&gt;&lt;p&gt;Working with design systems involves a level of &lt;strong&gt;structuring and organization&lt;/strong&gt;
 that is also very useful for creating this type of test. There’s a myth
 that design systems limit creativity. This is not true. Design systems 
help solve the “bureaucratic” part of design, so we can actually have 
more time for what matters: in this case, testing accessibility and 
building more and more products and services that are truly accessible 
to the greatest number of people.&lt;/p&gt;&lt;h2 id="example-file"&gt;Example File&lt;/h2&gt;&lt;p&gt;It’s
 always easier to see an example than just read a description of a 
process. If this is true in many disciplines of knowledge, in design, 
this premise makes even more sense. Therefore, in this &lt;a href="https://www.figma.com/community/file/1600134823556764105"&gt;Figma file&lt;/a&gt;, freely published and openly available to the community, you’ll find a &lt;strong&gt;practical example of the entire testing process&lt;/strong&gt;
 described here. Remember that this is just an example. There may be 
countless ways to perform this type of test within the context of a 
Figma file.&lt;/p&gt;&lt;figure class="break-out article__image"&gt;&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/19-community.png"&gt;&lt;img alt="Visualization for the Figma file on testing font scaling" height="533" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/19-community.png" width="800" /&gt;&lt;/a&gt;&lt;figcaption class="op-vertical-bottom"&gt;(&lt;a href="https://files.smashing.media/articles/testing-font-scaling-accessibility-figma-variables/19-community.png"&gt;Large preview&lt;/a&gt;)&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;Be
 sure to look at this approach with a critical eye. It’s a suggestion 
for testing font size increases that follows a specific process. Despite
 this, the approach should be adapted to your team’s specific reality, 
processes, and level of maturity. Simply copying formulas from other 
teams without understanding if they make sense in our own context is a 
sure way to make accessibility efforts disproportionate. Every situation
 is unique. This approach attempts to simplify accessibility work as 
much as possible in this specific context. And remember: if something 
happens, however small, it’s a step forward, not a step backward. And 
that should be celebrated by everyone on the team.&lt;/p&gt;</description><link>http://honeyvig.blogspot.com/2026/04/testing-font-scaling-for-accessibility.html</link><author>noreply@blogger.com (H)</author><thr:total>0</thr:total></item></channel></rss>