February 10, 2021

UX Engineering for design systems

Intro

Because UX Engineering is a relatively new role and the responsibilities can widely shift depending on the company, it can be challenging to explain to folks what we actually do for a living.

Geometric shape patterns in a grid

What's a UX Engineer?

Generally speaking, a UXE (User Experience Engineer) is someone who uses design thinking and user behavioral data to implement solutions with code.

A UXE's skills can be considered a subset of frontend development in that they are focused more on the front of frontend and translating design into code as close as possible.

While this role seems like a perfect fit for design systems, UXE's can flourish in any team that requires close collaboration between design and development.

Facilitating design alignment

Our design team includes representation from each of our business units, to make sure each product has a voice within the system.

One of my main responsibilities is to ensure our customers have consistent experiences. This means that we need a shared, common understanding of how a component should look and function in any platform and product.

Someone holding a phone with a laptop in the background

To help designers on our team understand which experiences are disparate amongst our products, we needed to establish (and commit to) explicit attributes within our design specs:

  • Anatomy : How we reference each element
  • States : What happens during a user interaction
  • Variants : Alternative forms of the component
  • Configurations : Supported options that end-users can choose from
  • Standard/Defaults : What comes out of the box

Creating a template in Figma with corresponding visuals for each business unit has been a great way to get buy-in for alignment.

As a UXE, it is also my responsibility to help designers understand how previous implementation may not have matched the original spec, and to create a plan to get us to our desired outcome.

Establishing constraints

When designing a component, it can be easy (and fun) to hand-pick certain values. It's also easy to accidentally pick a wrong value from the system when building out a new component.

This is how we end up with scenarios where placeholder typography in a textarea could differ than what was established previously for a standard input, when really design had intended them to share the same attributes.

A text input with placeholder text

A textarea with placeholder text that's styled differently

UXE's typically work with designers to explain the impact of design decisions (or confirm this wasn't a mistake in the spec) so that situations like this don't happen.

It also means we sometimes need to act as negotiators in order to strengthen durable logic within our system.

Architecting scalable blueprints

Because we are responsible for making sure a component accurately reflects design specifications, it's crucial that a component supports the same logic, plus future considerations.

Anticipating how a designer would want to modify a component also helps inform decisions around which attributes need to be stored as design tokens.

Strong architecture ensures less code repetition, helps with open-source contribution, and provides a foundation that helps guide scalability discussions.

An architect sketching a blueprint

Blueprint decisions include:

  • Defining the relationship between components
  • Defining the relationship between parent and child components
  • Determining if a variant is a separate component or defined through a prop
  • Establishing what configurable aspects get exposed to an end user
  • Creating and implementing design tokens

UXE's should constantly be asking:

How would someone want to implement this component?

The more time and care that can be invested at this stage, the less likely the team will need to implement a breaking change in the future.

Optimizing performance

While this article has emphasized making sure the component looks and behaves as expected, we also need to look at the bigger picture with how our decisions impact the rest of the design system ecosystem.

An optimized component includes evaluating:

  • Bundle size
  • Tree shaking
  • CSS over SVG
  • Asynchronous loading
  • Strong types

You can have the most customizable component on the planet, but if it takes ages to load, no one will use it.

Promoting and enforcing accessibility

By the time a component is ready to be coded, the design should adhere to minimum accessibility requirements including:

  • Typography
  • Line length
  • Contrast ratios
  • Minimum tappable area

Beyond this, a UXE needs to consider other interactions that may not have been uncovered during the design-focused part of the team's workflow.

A pair of glasses looking at an out of focus neighborhood

Typically, my accessibility checklist includes:

  • High contrast mode
  • Reduced motion styling
  • Alt text/aria props
  • Keyboard navigation
  • Dark mode support

Incorporating these aspects into the component is only one part of how we help ensure accessible experiences. We also need to help end-users (product developers) understand what they need to consider during implementation.

I find it helpful to bake in as much accessibility logic possible to mitigate risk that user will forget to incorporate it. For example, if a user doesn't supply a value for a label, you can make it a requirement that a user must provide an aria-label value instead.

This not only helps ensure the experience is accessible, but also educates users on best practices.

Writing tests

Writing tests ensures that the logic behind the component is reflected accurately in visual snapshots.

Typically, you want to test against:

  • Whether elements did or didn't render
  • If certain classes were applied
  • The render matches values from the design specs

At Intuit, we open-sourced proof, a test runner for Storybook!

Providing demos & documentation

After all the alignment conversations, architectural back-and-forths, and code iterations... we finally have something to show for it! 🎉

Providing a curated set of configurable examples and implementation documentation is the most visible part of a UXE's contribution to the project.

Storybook logo

In order to help our users navigate our Storybook, we created a common story structure so that users could quickly find what they needed.

Storybook sidebar

  • Playground : The standard configuration of a component, with full knob control
  • Showcase : A bird's eye view of supported variants
  • Features : Shortcuts to common knob configurations

At Intuit, we encourage teams to experiment and share feedback with what does and doesn't work. With user-backed data, we then work to graduate these offerings into the design system for everyone to use.

More details: How Intuit leverages Storybook and its plugins

Iterative reviews

I believe in sharing early, and sharing often.

While working on a component, each pushed commit generates a new Storybook link that anyone can review and comment on within GitHub. The benefit of this is that feedback doesn't get lost in Slack, and we can keep track of change requests.

To standardize how teams provide component demos, we include Storybook as part of our Design Systems CLI.

Advocating for the community

As part of the design systems team, the UXE is also responsible for being an advocate for both product designers and developers.

This includes:

  • Helping users onboard to the system
  • Answering questions
  • Making sure their voice is heard during sprint planning
  • Addressing feedback
  • Guiding users to the right team members

Calendly logo

It's easy to get overwhelmed by this run-the-business type of work. Conducting office hours using Calendly is a great way to make sure you can stay connected to the community and guard your time (and sanity).

What success looks like

Because we have to switch gears so often and interact with so many people, it can be challenging for folks to get a full sense of the work involved.

A successful UXE is someone who:

  • Goes with the flow and doesn't mind throwing away code to make something better
  • Feels comfortable explaining technical constraints and requirements to non-technical audiences
  • Tends to push back on one-off, unscalable designs
  • Puts ego aside to listen to the community AND willing to collaborate on solutions
  • Has intuition on how to add extra polish to an experience

I've found what's worked best is to include all disciplines in a JIRA board so that everyone is aware of what tasks need to be completed until we're ready to ship.

Passion led us here

Wrapping up

Even though UX Engineering is still in its infancy, the need for this type of role has been around for ages.

I'm excited to see more of these opportunities pop up, and super happy I was able to make the role what it is for our team.

For additional reading, I definitely recommend checking out Emma Bostian's article on UX Engineering.

If you aren't a UXE but thought this article highlights what you do or want to do, then I definitely encourage you to apply for this type of role! Cheers.

← All posts