UX Design Patterns

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:

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.