Marten Bjork

Case Study: Designing a Data Collection Widget

AlternativeTo is a software discovery site, helping you find alternatives to the apps you love and hate. I've been helping them develop a new version of their platform. Having good data is key to them, so they wanted to develop a “data collection widget” that lets their users answer questions about different apps (“Why do you like Figma?”).

Over ~12 days we planned and implemented this feature. The team consisted of me (design, React implementation), Ola (CTO, back-end) and Markus (CEO, product owner).

Planning

In previous design sprints, we learned that we must be very clear about what we're actually discussing. Otherwise it's easy to have one person thinking about typography, another about colors and a third one about the content. This is especially true when working remotely — you can't read body language or see what the other person is looking at.

So, this time we tried to be more deliberate in our design discussions. The first design aspect we discussed was where to place the widget. We wanted it to be visible, but not annoying. I drew up some examples so to guide the discussion.

Examples of different positions for the data collection widget on desktop screens

Each position comes with it's own connotation: Upper left corner is “allow notifications?” land. A banner at the bottom screen screams “cookie banner”. A modal over the page is visible but annoying. After some debate, we decided to use the lower right corner on desktop and use a banner-style toggle on mobile.

Next, I sketched up the bare bones of the widget:

A wireframe pointing out the main aspects of the widget: the title, close button, skip button, next button, pagination indicators and the area where the child view is rendered.

This is a quick step that saves a lot of time later. We caught a lot of minor design errors just by thinking everything through on a wireframe level.

A wireframe sketching showing two modal views. The second one has been optimized so that there are fewer buttons.

After some iterations we had simplified the widget a lot:

A wireframe sketch of the final modal. The UI has been redesigned so that the title, pagination dots, skip link and close button all fits in the modal's header.

Visual design

Next, we moved on to visual design. I quickly designed a few different versions of the modal:

Three different modal styles. The first one is minimalist, the second one has a blue header and the third one has a grey header with the current user's profile picture in it.

Presenting multiple versions is very important when collaborating on design. It's what enables the discussions that move the project forward: “this design may not be too anonymous”, “this design feels too dull”… The real progress is made during these discussions — not when pushing pixels into perfection in Figma.

Next, I designed a bunch of different child views. This is a stress test — can our format handle all the UIs we may want to render down the road? Can different widgets live in the same container in a coherent way?

A mosaic of the same modal but with different types of forms in it.

Finally, we had the entire flow figured out. We had simplified the overall UI. The child views felt future-proof and well designed.

Six different versions of the same modal. The versions are labeled, showing how the user moves through the user interface.

Live documentation

Throughout our projects, we write a lot. We write for a few hours and then invite the rest of the team to comment. It's much more efficient and robust than asking questions on Slack all day. In this projects, we had various documents that we bounced back and forth, slowly improving the specification.

Screenshots of three different documents. First one shows the product owner's thought on the projects, the second one shows my design notes and the third one shows my notes on the react implementation of the modal.

Implementation

With the design and and specification in place, it was time to implement the widget in the new React (next.js) platform. The key points of the spec were:

  • It should be possible to render the data collection widget anywhere

  • It should be easy to render 1 or more child widgets — in any order

  • Child views should modular and live in isolation from the parent component (no leaky abstractions)

I created a top-level <DataCollector /> component that abstracts all the complexity away. This is all you need to kick off the data collection flow:

<DataCollector appId={123} widgets={['AskToLogin', 'FavoriteApp', 'FavoriteFeatures']} onClose={() => this.myCustomCallback()} />

It's easy to add new capabilities to the data collection system down the road. The child views can do whatever they want as long as they call props.done() at some point.

const MyCustomView = (props: ChildViewProps) => ( <button onClick={() => props.done()}>Go to next view</button> )

In reality, the child views are much more complicated — they include side effects and third party libraries. But to get started, you just new a few lines of code.

Finally, to enable a new child view, it needs to be registered in the componentMapping config:

/** * Define available widgets */ componentMapping: DataCollectionComponentMap = { MyCustomView: { component: MyCustomView, skippable: false, hideUI: true }, BestAlternative: { component: BestAlternative, skippable: true, hideUI: false }, Comment: { component: Comment, skippable: true, hideUI: false }, End: { component: End, skippable: false, hideUI: true, props: { done: () => this.hide() } } };

Shipped!

The feature is now in beta at AlternativeTo.