PageSourceSearch

https://ignorethecode.net/blog/2026/08/09/toggles_considered_harmful/

html ignorethecode.net collected 2026-10-02 04:27:22 UTC 7,781 bytes, 114 lines download raw bytes

1<!DOCTYPE html>
2<html lang="en">
3	<head>
4		<meta charset="utf-8">
5		<meta name="viewport" content="width=device-width, initial-scale=1">
6		<meta name="color-scheme" content="light dark">
7		
7<script>(function(){try{var m=document.cookie.match(/(?:^|; )theme=(dark|light)/);if(m)document.documentElement.setAttribute('data-theme',m[1]);}catch(e){}})();</script>
7
8		<title>ignore the code: Toggles Considered Harmful</title>
9		<meta name="generator" content="Gorgon" />
10		<link rel="apple-touch-icon" href="/blog_images/iphone.png"/>
11		<link rel="alternate" type="application/rss+xml" title="ignore the code RSS Feed" href="//ignorethecode.net/blog/rss/" />
12		
12<script src="/blog/js/footnotes.js" defer></script>
12
13		
13<script src="/blog/js/dates.js" defer></script>
13
14		
14<script src="/blog/js/theme.js" defer></script>
14
15		<link rel="stylesheet" href="/blog_images/fonts.css">
16		<link rel="stylesheet" href="/blog_images/carbon.css" type="text/css">
17		<link rel="stylesheet" href="/blog_images/blog.css" type="text/css">
18		<link rel="shorturl" href="https://ignco.de/818" />
19		<link rel="shortlink" href="https://ignco.de/818" />
20		<link rev="canonical" type="text/html" href="https://ignco.de/818" />
21		<link rel="canonical" href="https://ignorethecode.net/blog/2026/08/09/toggles_considered_harmful/" />
22		<link rel="stylesheet" href="/blog_images/article.css" type="text/css" media="screen">
23	</head>
24	<body>
25		<div id="content">
26			<main id="posts">
27	
28	<div class="post" id="post_818">
29		<div class="text target">
30			<div class="date"><a href="/blog/2026/08/09/toggles_considered_harmful/">August 9, 2026</a></div>
31						<h1 class="posttitle">
32				<a href="/blog/2026/08/09/toggles_considered_harmful/" rel="bookmark" title="Permanent Link to Toggles Considered Harmful">Toggles Considered Harmful</a>
33			</h1>
34						<p>I just read <a href="https://unsung.aresluna.org/seeing-like-a-state/">this post</a> from Marcin Wichary's Unsung, where he points out a peculiar macOS dialog box that shows boolean toggles in four different shades of grey:</p>
35
36<p><img src="/upload/818/toggles.png" alt="macOS's Link to Mac or iPad dialog box, showing four settings implemented as toggles, each in a different shade of grey" /></p>
37
38<p>Marcin offers some improvements, but the actual problem is fundamental to macOS: these types of toggles are bad UI controls and should simply not exist.</p>
39
40<p>I think toggles originated on iOS, where they replaced checkboxes. I suspect the reason is that they feel more tactile on a touchscreen, have a larger touch target, and resemble physical switches - Apple's original UI design approach for iOS valued this kind of skeuomorphism.</p>
41
42<p>Toggles make sense in the real, physical world because of their mechanical properties. But even there, they need additional affordances to work. For example, this power strip has a toggle switch to turn it on and off:</p>
43
44<p><img src="/upload/818/powerstrip.jpg" alt="Toggle on a power strip with &quot;Reset&quot; and &quot;Off&quot; labels" /></p>
45
46<p>Note that there are labels for each state, and a light to indicate the current state. That's because the toggle itself is symmetrical. There is no obvious way to tell whether it is on or off.</p>
47
48<p>Now let's go back to the digital toggle:</p>
49
50<p><img src="/upload/818/digital-toggle.png" alt="A digital toggle" /></p>
51
52<p>Is this toggle on or off? If you don't already know that "left" means "off" and "right" means "on", you have absolutely no way to tell.</p>
53
54<p>Apple's attempts to make toggle states more obvious ultimately created the confusing situation in the original screenshot. Therefore, the most expedient solution to the original UI problem is simply to use a control whose state is obvious.</p>
55
56<p><img src="/upload/818/checkboxes.png" alt="The same screen, toggles replaced with checkboxes, now makes the checked/unchecked and enabled/disabled states obvious" /></p>
57
58<p><em>Update:</em> <a href="https://lobste.rs/s/ulinck/toggles_considered_harmful">Discussion on lobste.rs</a>, including <a href="https://lobste.rs/s/ulinck/toggles_considered_harmful#c_ysqdgq">this point</a> I wasn't aware of:</p>
59
60<blockquote>
61  <p>There is an accessibility setting on macOS named "differentiate without color", which does help by showing little on/off indicators on the toggles.</p>
62</blockquote>
63
64<p>If your System Settings search field also doesn't work, it's under Display. Enabled.</p>
65						<div class="shorturl">
66				<p>If you require a short url to link to this article, please use <b><a href="https://ignco.de/818">https://ignco.de/818</a></b></p>
67			</div>
68					</div>
69	</div>
70		<img class="swirly" src="/blog_images/swirly.png" alt="" width="255" height="78" loading="lazy" decoding="async">
71	<a href="https://pragprog.com/book/lmuse2/designed-for-use-second-edition"><img style="float:left;display:block;margin-right:10px;margin-bottom:200px;margin-top:20px;" src="/blog_images/designed_for_use_second_edition.jpg" alt="designed for use cover" width="200" height="183" /></a><p><b>But wait, there's more!</b></p><p>Want to read more like this? Buy my book's second edition! <i>Designed for Use: Create Usable Interfaces for Applications and the Web</i> is now available DRM-free directly from <a href="https://pragprog.com/book/lmuse2/designed-for-use
71-second-edition">The Pragmatic Programmers</a>. Or you can get it <a href="http://www.amazon.com/gp/product/1680501607/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1680501607&linkCode=as2&tag=wisegamersch-20&linkId=74A2IPF6GRYBDDTA">on Amazon</a>, where it's also available in <a href="http://amzn.to/WMI37B">Chinese</a> and <a href="http://www.amazon.jp/dp/4873116082">Japanese</a>.</main><!--posts-->
72<aside id="sidebar">
73	<div class="title">
74		<a href="/" id="titleignore">ignore<br></a>
75		<a href="/" id="titlethe">the<br></a>
76		<a href="/" id="titlecode">code</a>
77	</div>
78	<div class="byline">
79		written by<br>
80		Lukas Mathis
81	</div>
82
83	<div class="info">
84		<a class="img" href="/"><img src="/blog_images/lukas.jpg" style="border-style:none;width:56px;height:95px;"></a><br><span
85				style="line-height:1.7;text-align:left;">Hi. My name is Lukas Mathis. <a
86					href="https://pragprog.com/titles/lmuse2/designed-for-use-second-edition/">I've written a book about usability</a>. It's been translated to <a
87					href="https://amzn.to/WMI37B">Chinese</a> and <a
88					href="https://www.amazon.jp/dp/4873116082">Japanese</a>. I make <a href="https://goodvantage.ch">software for NGOs at Goodvantage</a>. You can reach me at 
88<script
89					type="text/javascript">
90				//<!--
91				document.write("<" + "a" + " hr" + "ef=\"" + "ma" + "il" + "to:" + "&#76;&#75;&#77;" + "&#064;" + "&#108;&#107;&#109;&#99;&#46;&#99;&#104;" + "\">" + "&#76;&#75;&#77;" + "&#064;" + "&#108;&#107;&#109;&#99;&#46;&#99;&#104;" + "<" + "/" + "a>")
92				// -->
93				</script>
93.</span><br><br>
94
95		<div><a style="border-style:none;" href="/blog/rss/"><img style="border-style:none;" src="/blog_images/rss.png"></a>
96			<a href="/blog/rss/">Subscribe via RSS</a></div>
97	</div><!--info-->
98
99	<div class="search">
100				<form action="/blog/" method="get" accept-charset="utf-8">
101			<label for="blogsearch">Search:</label><br>
102			<input type="search" id="blogsearch" value="" name="query" results="5" placeholder="Search"
103			       autosave="ch.ignorethecode.blog.search">
104		</form>
105	</div><!--search-->
106	<div>or <a href="/blog/browse/">browse the archives</a>.</div>
107	<div>
108		<button class="theme-toggle" type="button" aria-label="Toggle dark mode"><span class="icon" aria-hidden="true">☾︎</span><span
109					class="lbl">Dark mode</span></button>
110	</div>
111</aside><!--sidebar-->
112</div><!--content-->
113<script defer src="https://analytics.pyramid-deliveries.ch/sa.js" data-domain="ignorethecode.net"></script>
113</body>
114</html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.