<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Ux on Build in Public</title><link>https://build.ralphmayr.com/tags/ux/</link><description>Recent content in Ux on Build in Public</description><generator>Hugo</generator><language>en-us</language><copyright>©️ Ralph Mayr 2026</copyright><lastBuildDate>Wed, 27 Aug 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://build.ralphmayr.com/tags/ux/index.xml" rel="self" type="application/rss+xml"/><item><title>The occasional toast can’t hurt</title><link>https://build.ralphmayr.com/posts/58-the-occasional-toast-cant-hurt/</link><pubDate>Wed, 27 Aug 2025 00:00:00 +0000</pubDate><guid>https://build.ralphmayr.com/posts/58-the-occasional-toast-cant-hurt/</guid><description>&lt;p&gt;Some of the designers and frontend devs I&amp;rsquo;ve worked with may remember my rants against toast notifications:&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Why do I need a success message for every action? I expect things to work. Only tell me when something breaks.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;But&amp;hellip; I&amp;rsquo;ll admit it: Sometimes toasts do have their merit.&lt;/p&gt;
&lt;p&gt;Two examples from poketto.me:&lt;/p&gt;
&lt;p&gt;🔹 Copy to clipboard (Podcast feed URL):&lt;/p&gt;
&lt;p&gt;When users click the &amp;ldquo;copy&amp;rdquo; button, the action happens instantly. But without any feedback, it feels&amp;hellip; awkward.&lt;/p&gt;</description></item><item><title>UX details sometimes make all the difference</title><link>https://build.ralphmayr.com/posts/55-ux-details-sometimes-make-all-the-difference/</link><pubDate>Sun, 24 Aug 2025 00:00:00 +0000</pubDate><guid>https://build.ralphmayr.com/posts/55-ux-details-sometimes-make-all-the-difference/</guid><description>&lt;p&gt;In
&lt;a href="../51-websockets-more-than-tech-vanity/"&gt;WebSockets: More than tech vanity&lt;/a&gt;, I talked about how poketto.me uses WebSockets to keep the UI in sync with async backend processes&amp;mdash;like translating, TTS, etc. Neat? Sure. Game-changing? Probably not. Just like I asked about AI in
&lt;a href="../54-ai-is-not-a-value-proposition/"&gt;AI is not a value proposition&lt;/a&gt;: where would you put that on the Business Model Canvas? It doesn&amp;rsquo;t really fit as a Value Proposition, does it?&lt;/p&gt;
&lt;p&gt;But that doesn&amp;rsquo;t mean it&amp;rsquo;s not important. Take Strava, for example.&lt;/p&gt;</description></item><item><title>WebSockets: More than tech vanity</title><link>https://build.ralphmayr.com/posts/51-websockets-more-than-tech-vanity/</link><pubDate>Wed, 20 Aug 2025 00:00:00 +0000</pubDate><guid>https://build.ralphmayr.com/posts/51-websockets-more-than-tech-vanity/</guid><description>&lt;p&gt;As I said in
&lt;a href="../18-socket-science-isnt-rocket-science-or-websockets-flask-socketio/"&gt;Socket science isn&amp;rsquo;t rocket science&lt;/a&gt;, WebSockets are quite easy to use with Python + Flask + Socket.IO on the backend and Angular + Socket.IO + RxJS on the frontend. But why bother? Dealing with asynchronous requests is more of a hassle than not. And for a &amp;ldquo;boring&amp;rdquo; app like poketto.me, aren&amp;rsquo;t synchronous HTTP requests/responses good enough?&lt;/p&gt;
&lt;p&gt;Here are two use cases where, despite the app&amp;rsquo;s apparent simplicity, asynchronous backend/frontend communication adds real value:&lt;/p&gt;</description></item><item><title>Consistency Beats Accuracy (Part 1)</title><link>https://build.ralphmayr.com/posts/38-consistency-beats-accuracy-part-1/</link><pubDate>Thu, 07 Aug 2025 00:00:00 +0000</pubDate><guid>https://build.ralphmayr.com/posts/38-consistency-beats-accuracy-part-1/</guid><description>&lt;p&gt;As I add more UI-heavy functionality to poketto.me (not all of it public yet), I keep running into the same issue: it&amp;rsquo;s tempting &amp;mdash; but risky &amp;mdash; to constantly invent new UI patterns and elements.&lt;/p&gt;
&lt;p&gt;Case in point: On the &lt;strong&gt;Saves&lt;/strong&gt; page, each saved item has a &lt;strong&gt;&amp;ldquo;more&amp;rdquo;&lt;/strong&gt; menu with actions like &lt;em&gt;Archive&lt;/em&gt;, &lt;em&gt;Delete&lt;/em&gt;, or &lt;em&gt;Edit Tags&lt;/em&gt;. But when I worked on the &lt;strong&gt;News Feed&lt;/strong&gt;, I completely overlooked this. Instead, I gave each news item its own &lt;strong&gt;action bar&lt;/strong&gt; &amp;mdash; dedicated buttons to save the item or, once saved, edit its tags. (See Exhibit A.)&lt;/p&gt;</description></item><item><title>Socket science isn’t rocket science! 🚀 Or: WebSockets + Flask + SocketIO = ❤️</title><link>https://build.ralphmayr.com/posts/18-socket-science-isnt-rocket-science-or-websockets-flask-socketio/</link><pubDate>Fri, 18 Jul 2025 00:00:00 +0000</pubDate><guid>https://build.ralphmayr.com/posts/18-socket-science-isnt-rocket-science-or-websockets-flask-socketio/</guid><description>&lt;p&gt;For some reason, async communication between a web app backend and the browser causes more anxiety than it should (guilty 🙋). I&amp;rsquo;ve had my fair share of headaches with WebSocket frameworks before, but for poketto.me, I tried a much simpler stack&amp;mdash;and was pleasantly surprised:&lt;/p&gt;
&lt;p&gt;➡️http backend: &lt;strong&gt;Flask&lt;/strong&gt; (
&lt;a href="https://flask.palletsprojects.com/en/stable/" target="_blank" rel="noopener noreferrer"&gt;https://flask.palletsprojects.com/en/stable/&lt;/a&gt;)&lt;br&gt;
➡️websocket backend: &lt;strong&gt;Flask-Socketio&lt;/strong&gt; (
&lt;a href="https://flask-socketio.readthedocs.io/en/latest/" target="_blank" rel="noopener noreferrer"&gt;https://flask-socketio.readthedocs.io/en/latest/&lt;/a&gt;)&lt;br&gt;
➡️websocket frontend: &lt;strong&gt;socketio-client&lt;/strong&gt; (
&lt;a href="https://www.npmjs.com/package/socket.io-client" target="_blank" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/socket.io-client&lt;/a&gt;)&lt;/p&gt;
&lt;h4 id="-backend-handling-connections-is-dead-simple"&gt;&lt;strong&gt;🔌 Backend: Handling connections is dead simple&lt;/strong&gt;&lt;/h4&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;@socketio.on(&amp;#39;connect&amp;#39;)
def handle_connect():
_, user_id = authenticate()
sid = request.sid
connected_clients[user_id] = sid
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="-sending-data-to-a-connected-client"&gt;&lt;strong&gt;📤 Sending data to a connected client&lt;/strong&gt;&lt;/h4&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;sid = connected_clients.get(user_id)\
if sid:
socketio.emit(&amp;#39;message&amp;#39;, {
&amp;#39;message_type&amp;#39;: &amp;#39;save_changed&amp;#39;,
&amp;#39;data&amp;#39;: {
&amp;#39;id&amp;#39;: save_id,
&amp;#39;state&amp;#39;: &amp;#39;archived&amp;#39;
}
}, to=sid)
#### **🖥️ Frontend: Receiving messages is just as easy**
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;const socket = io(environment.WS_BASE_URL, {&lt;/p&gt;</description></item></channel></rss>