A system for infinite UI possibilities

2023

Case study to come

We were missing capabilities

Our booking module's personalization capabilities were far beyond what a Michelin-starred restaurant needs to keep their experience consistent across every channel. So we decided to do something about it.

After benchmarking the best personalization tools online, the Engineering Manager, the Product Manager, and I decided on which aspects we would allow restaurants to personalize: fonts, visuals, and colors.

Design principles

I decided to tackle this with a few guiding principles:

  1. Always keep accessibility in mind
  2. Make it scalable

And so we decided to bring our users the Design Kit

A new feature built for Michelin restaurants and groups with a strong brand identity across their locations.

A space for them to set the elements related to their brand, so that identity could be carried through into the booking module — and into many more user touchpoints down the line.

Implementing fonts

  1. Web-based — to make implementation and licensing/usage rights straightforward.
  2. Limit some types to headings only — to make sure body text would always stay easy to read.
  3. A request-based system — after adding a set of the most popular Google Fonts, we set up an email address so clients could request new fonts. Each request was checked to make sure the font matched their brand and had extended coverage for language-specific characters (e.g. characters like "ň").

Implementing visuals

  1. Support the most standard logo and picture formats — so restaurants could use assets they already had, without needing new exports.
  2. Seamless integration — we implemented an extension that could automatically detect and remove a solid color background from a client's logo, so it would sit cleanly on any surface.

Implementing colors

1. Primary (accent) and secondary (background) colors

We let restaurants define these two colors to match their brand identity — while nudging them toward better accessibility along the way.

2. Text and UI elements

The real challenge was deciding how to derive the color of text and UI elements automatically, so that everything stayed accessible and WCAG-compliant, whatever accent/background combination a restaurant chose.

Every text and UI element ends up either black or white, depending on the color it sits on top of.

We used a WCAG contrast checker to determine, in real time, whether black or white gave better contrast against the chosen accent color:

Choosing the better contrast color for a button

I applied the same logic to background colors, to determine the color of labels, placeholders, legends, and other UI elements sitting on top of them:

Choosing the better contrast color for UI elements on top of the background

Here's how the same accent/background pairing plays out for a "Book now" button depending on whether the background is light or dark:

Not enough contrast choosen warns the user
Color contrast is good

3. Make it all dynamic

In any interface, colors aren't static — they shift as we interact with elements (hover, focus, press, disabled).

First approach: an overlay. My initial idea was to shift the perceived color on interaction using a semi-transparent overlay (e.g. a black overlay at 8–24% for hover, 16–48% for pressed, a white stroke at 40% for focus, and a fixed gray at 100% for disabled):

A dismissed approach to giving dynamic states to buttons

This approach didn't hold up for every case, so I went looking for a new one.

Second approach: Lightness manipulation. Since we were already calculating whether black or white had better contrast against a given color, we realized we could base the interaction states on that same calculation. Researching other design systems, I found a helpful model in IBM's Carbon design system.

The idea: convert the base color from HEX to HSL, and manipulate its Lightness value.

Hue, Saturation, Lightness model

The principle rests on a threshold of perceived darkness — for simplicity, we placed it around 40L. In practice, though, we start from a simpler question: does white or black give higher contrast against this color? From there we can lighten or darken the base color as the user interacts with the element:

Darken range (100–41) vs. lighten range (40–0)

Applied to a full range of base colors, across default and hover states, buttons shift consistently up or down the Lightness scale — lighter base colors darken by 10L on hover, darker base colors lighten by 10L on hover:

An example of using variations in Light to determine the Hover state color

Bringing it to life: the Design Kit page

With the principles settled, we moved on to implementation — starting with the Design Kit page itself inside TheFork Manager, where restaurants set their fonts, visuals, and colors. (The original screenshot of this page was not available/renders blank in the source deck.)

Usage guide

Alongside the flows and screens, we produced a guide documenting how each element should behave — tokenizing properties like background-color ± 10L so the logic could be reused consistently across components.

Pax selector

Using the accent color range:

Default, Hover, Pressed, and Focus states

Date selector

Shown on both a dark and a light background, following the same accent/background logic:

A date selector showing Selected (top) and Hover (below) states

Offer cards

With selected, hover, and default states, again on both backgrounds:

(Top to bottom) Default, Hover, Hover on Read More, Selected and Focus states.

Illustrations

A consistent icon set adapted to the accent color, on both backgrounds:

Using tokens we defined dynamic Accent color variations to manage illustrations' color
Other case studies