UX Design Patterns
Published on:
I recently watched this recording of a talk about Desktop UX by Scott Jenson.
This got me thinking about some UX patterns I've found myself including in my work building internal tools. Here are some of those below.
CycleableDateTime
We have a lot more freedom, I think, when building internal tools than consumer facing products. One UX pattern I've particularly loved is what I call:
<CycleableDateTime />
Users often want to view timestamps in different formats depending on context. A single user may also want to view timestamps in different formats depending on the web page they are on. The options are:
- UTC time zone
- Local time zone
- Relative time
CycleableDateTime is a component I've started bringing with me in every internal web app. A global, app-wide configuration value controls the format used for all instances. Clicking any CycleableDateTime component causes them all to toggle and flip through these three modes.
Try it below.
<CycleableDateTime value={new Date("2025-01-18T05:22:23.000Z")} />
<CycleableDateTime value={new Date("2022-08-10T19:23:54.000Z")} />
<CycleableDateTime value={new Date("2020-04-19T13:17:32.000Z")} />
Which renders:
Hovering over one provides the current format.
Global Loader
All of our applications load data. Data loading can be triggered automatically, programmatically, or by a user clicking a button. It's nice to see when data is loading across our app. And thus was born:
<GlobalQueryLoader />
All the internal apps I use leverage TanStack Query which helpfully exports the
hook useIsFetching. Whenever this hook's return value is greater than 0,
something is being fetched and the spinner is rendered.
Normally I place the spinner in the navbar or some part of the page that is consistently available and visible across all routes. It's a small detail that makes it easy to understand when the page is loading new data.
Entity Detail Layouts
Some people want entity detail pages such that all information is inline on the
page, with each section expandable/collapsible. Some may prefer a tabbed
interface so the page isn't overwhelming, others may prefer a mix between the
two like a sidebar with links to each section via the id property. And there
are still other formats we can think of and develop. And each can be useful in
different situations.
Nothing about these layout options is related to the actual components that render the information; it's only about how those components get laid out on the page:
Acme Workspace
Active customer workspace with 24 members.
Command Palettes
Engineers love command palettes. They are in all our tools and many engineer
focused websites. But implementing them can be annoying if we have to manually
register actions into the command palette for each of our pages. Keeping that up
to date as we add new features, move features from one page to another or remove
them is a hassle. We need this capability to exist at a lower level of
abstraction: <Button>, <Link>, <Tab>, <FormSubmit> etc should
automatically register their actions.
Rendering a <Button> on the page automatically adds its action to the
command palette. The command palette becomes contextually aware of the
page and stays in sync as we make changes.
Try CMD+k / Ctrl+k on this page. You'll have options to navigate to all the linked pages, toggle light and dark mode, control the above Entity Detail Layout and select various sections.
Summary
What's important about these UX patterns is their ease of access.
Swapping the timestamp formatting doesn't require digging through some settings menu buried in a rarely used part of the application. It's right there in front of you. It is discoverable and actionable without being in your face. The ability to control the layout is right there on the screen. The loading indicator shows when anything is loading, and the command palette has a dedicated icon in the navbar and once you use it with the combo, its burned into your mind and expected.
These are little ways to give users more feedback and more control over the software they use. It makes our tools more flexible.
What is most important to me as well is these are all compositional. Adding one does not interfere with the other but can make it more powerful. This is how we build up.