← All case studies

UHDS, Hotels.com’s first design system.

Lead Product Designer, Design SystemsUHDS, Hotels.com2019-2110 min read

UHDS motion easing curves
0 → 1
Hotels.com’s first design system
5
Products sharing one design language
100%
Of web library with coded counterpart

Built alongside the Hotels.com rebuild, UHDS became the design language for five products: web, iOS, Android, CRM and social. I led it for three years, from the first reused component to the migration that replaced it.

It started as a side project

Hotels.com was rebuilding its site as a Progressive Web App, a single React application assembled from shared components rather than a collection of individually built pages. We were designing it all from scratch, so on each new screen I’d use as much as I could of what we had already drawn, and those pieces got collected, named and written down with the values they shared. Before anyone had proposed a design system, we had the beginnings of one.

For that first stretch the system and the product were one piece of work: design a screen, pull out what was reusable, build it, bring it back. We sat with the developers, most of the time at the same desk, and because the rebuild was judged on speed, what a component cost to render was part of designing it. Three of us kept it moving and made the case to leadership every week, until they invested in it and put developers on it. The rebuild case study has the argument we made.

"What I valued most was how Joe engaged with the engineering teams - not just delivering specs, but taking the time to understand the technical challenges of implementing a complex design system and using that to inform his work... That kind of design and engineering alignment is hard to find, and any team building or scaling a design system would benefit from having Joe bring that to their work."

Niall Johnson, Senior Engineering Manager, Hotels.com

From atoms to foundations

We started small, taking a lead from Brad Frost’s atomic design: text, buttons, badges, images, the pieces that assemble into larger ones. For a while it was a pattern library rather than a design system. On web, every one shipped with a coded counterpart, so anything a designer picked up was already built.

Four columns showing how the UI breaks into levels. Design tokens and foundations: colour swatches, type sizes and icons. Components: an image, badges, list items and a primary button. Patterns: a property card assembled from those components. Section and view: that card placed in a fuller page layout.
Foundations, components, patterns, sections and views. Each level is assembled from the one below, so less gets rebuilt.

As those pieces multiplied, the decisions underneath them had to be settled rather than made again each time. We refactored colour into ramps off the brand hues, built a type scale, worked out a sizing scale and density rules for type, and declared the foundations as tokens. Changing one then moved through the whole system instead of being re-set screen by screen.

Elevation tokens, lifted apart. Hover or tap a panel to press it back down.
The UHDS elevation spec: a front view of a screen with five raised elements keyed A to E as chrome top, lift, over, float and raise; a side view plotting the same five on a z-axis in spacing units; and a panel of chrome and component shadow values with a table of names and example usage.
Every raised surface with elevation values.

Motion got the same treatment. We built a framework of easing curves and durations, encoded them as tokens, and documented which to use and why, matching a duration to the distance travelled and an easing to the component’s job.

The easing set, each with a marker running under its curve.

A shared vocabulary

Sketch had no concept of component properties, so we encoded them in the name: Item, Purpose, Scale, Style, Content. "Label / Positive / 14 / Light / Icon + Text" was a component’s configuration written out, each segment standing in for a prop in React. We spent a long time working that taxonomy out with the development team, and it was one of the more useful things we did.

The names spread past the design team. In a meeting about a new screen, a PM could say "let’s use the text plus image option" and the designer and the engineer both knew which component was meant, in which configuration.

Sketch’s nested symbol menu cascading through the badge taxonomy. The first column lists item types - Count, Guest Review, Label, Map Pin, Notification - with Label selected. The second lists purposes - Brand, Gold, Negative, Neutral, Positive, Purple, Silver, Unavailable - with Positive selected. The third lists sizes 12 and 14, and the fourth lists styles: Heavy, Heavy with icon and text, Light, Light with icon and text, Light with outline, and Light with outline plus icon and text.
Component naming had a direct correspondence to taxonomy.
SegmentOptions
ItemLabel · Count · Guest Review · Map Pin · Notification
PurposeNeutral · Brand · Purple · Silver · Gold · Positive · Negative · Unavailable
Scale14px · 12px
StyleHeavy · Light + Outline · Light
ContentText · Icon + Text

Patterns and the layout underneath them

Certain blocks kept reappearing, so we consolidated them into patterns: combinations of components solving a recurring problem, assembled only from what already existed. Each was drawn with every element it could contain on show, so a designer hid what they didn’t need. They were then encoded in Storybook. The documentation covered the thinking and historical context as well as the UI, so a decision got reused instead of remade.

Four property cards in a two by two grid, labelled Positive, Neutral, Positive Unavailable and Neutral Unavailable. The two available cards carry a photo carousel, a favourite heart, the property name and star rating, a guest review score - 9.4 Exceptional in green, 7.4 Good in grey - a TripAdvisor bubble rating, and a price. The two unavailable cards collapse to a compact row with a no availability message above, a thumbnail in place of the carousel, the review score desaturated to grey, and Sold out where the price was.
The property card in four states, with the review component adapting to sentiment and availability.

Underneath sat a layout system built so components could be reordered. Spacing was consistent between the items in a block and between the blocks themselves, so blocks nested and nothing needed a bespoke measurement.

The Hotels.com property page with the layout system’s spacing overlaid: every gap between blocks highlighted and labelled with its value, from the gallery and title down through price, reviews and room choices.
A page-level view showing section spacing and blocks within.

Drawing the line between system and product

Desktop put the system under real strain. It had been built mobile-only, so a lot of it did not hold up at a second set of widths. Working out what could stay shared and what had to flex is told on the rebuild case study.

The UHDS scaling map: channel, device, grid columns, margins and gutters, heading upscale, container behaviour and page, section and component spacing, all plotted against the 0, 576, 992 and 1200+ breakpoints.
The scaling map: channel, grid, headings, container and spacing against four breakpoints.

Once the desktop proof of concept landed, the business wanted everyone on it, and the role split. A colleague and I took the system, and the product side grew to around twenty designers. What made it workable was being explicit about where system design ended and product design began.

LevelDesign system teamProduct teams
Tokens and foundationsMaintained, governed and documentedUsed them
ComponentsBuilt, documented, specced for scale and densityUsed them
PatternsDocumentation, spacing rules, design principlesContent, hierarchy and what displays
Sections and viewsGrid options, spacing, adapting across channelsStructure, placement, and the research behind it

Teaching a team that had never used one

Most of the designers had never worked in a design system and were used to free rein, so a large part of the job became education. Developers took to it quickly. The PMs were the sceptics: the site ran on MVT testing at high velocity and they assumed a system would get in the way.

A lot of the teaching ended up in the documentation. We put the design language, the components and the principles behind them on a zeroheight site, and added a knowledge hub for designing with the system. At handoff, Zeplin showed developers the real components under their real names.

Pages from the UHDS documentation: the zeroheight site showing image ratio guidance under a Design Language, Components and Principles nav, the Hotels.com brand guidelines, primary CTA specifications in default and inverse, and annotated component states.
The documentation site, the brand guidelines and the component specs behind them.

Testing went the other way. It had been page-level and small: individual colours and micro-enhancements injected into specific pages. Designing through the system moved people up a level, and a test could run across a whole experience instead of page by page. We could test more broadly and faster at the same time. We ran talks and workshops for designers, developers and PMs on both.

Measuring whether it was working

The UX team already ran a quarterly pulse, so we added a design system section to it: three statements, each scored out of ten. It gave us a read we had never had, and something to point at when leadership asked what the system was worth.

StatementQ1Q2Q3
The design system and toolkit enables me to work faster5.77.17.1
There are enough components for me to produce quality work5.86.36.7
Finding components and using the Sketch toolkit is easy5.86.57.7

All three moved the right way. Speed went first and fastest, then held while coverage caught up behind it. The scores were never the point on their own: each round we took the weakest one into deep dives with the team, worked out what sat behind it, and put the fix in the next quarter’s plan.

Moving the whole library to Figma

Expedia Group was working out how its design systems could converge, and nothing could be shared while we were in different tools. The first agreement was React in code and Figma in design, by a fixed date.

We worked through it component by component, teaching everyone Figma as we went because almost nobody had used it. Two days before we were due to finish, Figma shipped auto layout. It changed how components should be built, and we decided that mattered more than the date, so we moved the deadline by a week or two and rebuilt the library on auto layout, every component responding to its content.

On top of it we built a page for every core surface at every breakpoint, listing every component and pattern it could contain in sequence rather than as a finished design. We called them kitchen sinks: a designer pasted one in and re-sorted it into the page they needed.

The search results kitchen sink: the same page laid out at four breakpoints side by side, from mobile through to wide desktop. Each column runs the full length of the results page - filters, the map prompt, property cards, inline modules, footer - with every component and pattern it could contain in sequence, and annotation blocks marking the sections.
Kitchen sink designs for search results: these show all available content patterns in situ for a range of scenarios.

Once every system was on Figma, designers from different brands and different systems could work in the same files in real time. None of the shared token work could have started without it.

Handing it over

Once everyone was in Figma, we were no longer the only people who could build components. We set up a Slack channel and kept every question in a thread so the answers stayed findable, ran open hours, and took bookings for one-to-one time. Teams had been working around us; after a while they started bringing us proposals.

We split the library into three kinds of component, each with its own rule about who could change it.

ComponentWho could change itWhich ones
OpenAny product team, approving their own changeA specific feature or pillar: Covid Cleanliness Banner, Hero Image, Payment Options
SharedAny product team, with the design system team approvingComplex or reused everywhere: Header, Footer, Property Card
CoreThe design system team onlyThe foundations: Search Query Module, Button, Badge

We treated anything bigger than a component as a pattern and handed those to the product teams, who were organised in pods around home, search, shopping and checkout. Each pod lead owned their patterns and documentation and published them into Figma for others to use as a starting point.

Getting the other channels onto it

UHDS had started on web, so web was already on it. Apps and CRM wanted the same design language, and social after them. None of them wanted to stop feature work to take on someone else’s library, and each had its own team and its own roadmap. So we gave them a first step they could reach.

The principle

We were aiming for a coherent look and feel across the channels rather than a shared implementation underneath. The code and the technology could vary, as long as the customer felt they were in one place.

That gave teams something they could sign up to, and we set it out as a ladder of four tiers they could climb at their own pace.

1 · Brand identifiers
Colour mapped from brand to UI, type, the three button styles, keylines, icons and lockups.
2 · Usability
Accessibility and industry standards: type size, controls, forms, spacing, one link pattern.
3 · Brand and UI alignment
Token alignment for radius, image ratio and shadow, then shared core components.
4 · North star
Shared tokens and components, a unified design system, and potential Expedia Group alignment.

The apps team took the ladder and ran it themselves. They built their own toolkit in Figma from the design language rather than consuming our library, and they were not on our tokens, so underneath the code had nothing in common with web. They carried the look and feel across and left the rest. Designs reached tier two on both iOS and Android before the eventual migration across to the group system.

Hotels.com iOS and Android screens at tier two: the same white canvas, red logo, type weights and button styles as web, on native chrome that differs between the two platforms.
iOS and Android at tier two, built on their own code with the same visual language.

CRM went a different way. We audited every campaign and component the channel was running, then built a toolkit with them: the hero and campaign layouts spec’d down to the type roles, each one paired with a real campaign so it was clear how to use it. The CRM and social teams then built the first campaign designs themselves from the key components and patterns we took across, and the channel moved off its old red mastheads onto the same white canvas and red logo as everything else.

The CRM email toolkit: hero and campaign layouts annotated with their type roles and button styles, each shown beside a finished Hotels.com campaign.
The CRM toolkit: every campaign layout spec’d against the system, and shown built.

The end of the road

As the group’s own system ramped up I was initially spending two days a week on EGDS, the Expedia Group Design System. The plan was to hand UHDS over and keep it running as I transitioned into a full-time role on EGDS. It was at this point that the business went to a house of brands strategy, the Hotels.com brand work was parked, and the handover stopped where it was. The group moved onto one shared platform, and that was the end of the road for UHDS.

The whole site had to migrate a second time, onto the EGDS stack. It was painful at the start and some of the finer design thinking got lost in the translation. The reasoning underneath it carried over: the size and spacing scales, the density rules, the way we had thought about type. UHDS became one of the four systems that merged into EGDS, and I went with it.

Before: four Hotels.com surfaces, each styled differently. Search and results carry a heavy red masthead, checkout uses a red header with grey form fields, and the CRM email is built on a red banner with blue links and mixed type.After: the same four surfaces on one design language. Every masthead is a white canvas with the red logo, headings and controls share the same type and shape, and the CRM email uses the same buttons and card treatment as the product.
Drag to compare. The same four surfaces on web, iOS, Android and CRM, before and after the design language went across them.

What I’d do differently

  1. Baseline the measures before the first component shipped. We agreed early how we’d judge the system: component coverage, design and tech debt, shipping velocity, team sentiment. I wrote the plan to track it, including usage analytics once we were in Figma, and it kept getting pushed behind delivery. The pulse questions were the only part that ran, so we could say how the team felt but never what the system saved.

  2. Write the contribution rules down sooner. We agreed changes case by case for a long time before the three tiers existed.

  3. Grow the team as adoption grew. Every new channel and every new designer added support, documentation and core work, and the team stayed the same size. Documentation was the part that could always wait another week. We won the argument for people once to get the system built, and I would make it again with every channel that came on.