Last fall, FiftyThree introduced Mix, a new way for users to collaborate on sketches and ideas in Paper. Though it’s only been a few months since launch, the Mix feature set has grown by leaps and bounds. One of the most requested features was the ability to search for friends. Unsurprisingly, Mix users wanted to […]
Last fall, FiftyThree introduced Mix, a new way for users to collaborate on sketches and ideas in Paper. Though it’s only been a few months since launch, the Mix feature set has grown by leaps and bounds. One of the most requested features was the ability to search for friends. Unsurprisingly, Mix users wanted to find and collaborate with people they already followed on Tumblr, Twitter and Facebook. Just before the new year we launched creator search in Paper and on Mix.
The biggest challenge we faced while building our web-based search was implementing a fluid text input. A fluid text input has a width that is defined by its content. If you have experience with web programming, you’ll recall that HTML text inputs are not naturally fluid. This post explores how we implemented a text input with no explicit width.
There are quite a few custom user interface features in our iPad app Paper, and text input is no different. When you edit the title of a Paper journal or enter text in the search field, you’ll notice that the type is centered in the UI. Not only are these text inputs visually appealing, they function to balance the on-screen elements.
The FiftyThree design and engineering teams recognize the importance of adhering to a design language that is intuitive, beautiful and, above all, consistent. Thus, keeping the Mix aesthetic and experience in step with all our products, especially Paper, has been a goal from the beginning.
As design-focused engineers and engineer-minded designers, we’re no strangers to constraints from both sides. Ultimately, well-defined constraints help guide us toward workable solutions and more quickly discard ill-conceived approaches. We had a general idea of what a fluid text input needed to do, but in order to differentiate between must-haves and nice-to-haves, we created a list to help gauge success:
Let’s review each constraint in more detail.
Native HTML text fields must have a defined size. If you don’t provide a size, the browser will render the element at a default width. In the figure below, x represents the width of the text input. x can be defined in one of three ways:
This was the toughest constraint of all because we needed to “break the rules” when it came to the way that browsers rendered text fields. We wanted the native behavior of a standard text input with the flexibility of an inline element.
We understand how text fields work because we have been using search engines for years. So we knew if we were going to tinker with a native HTML text field, the final version would have to work exactly like we expected in regards to text selection. We’d have to be able to insert our cursor anywhere within the typed content, use the keyboard to move it, and use the shift and arrow keys to start/move the selection area.
placeholder attribute for text fields has had a rough upbringing. Initially, browser vendors implemented
placeholder behavior as they wished; some vendors didn’t support it at all. In the past few years browsers have been kinder to
placeholders and the behavior has normalized.
Although the interactions for
placeholder attributes have become consistent, we still wanted to ensure that the placeholder copy would behave similarly to those in Paper text inputs. For style consistency and to future-proof our implementation, we decided to create our own custom placeholder text.
As one would probably expect, most Mix users also use Paper, which means that they own or have access to iPads. We know that usage of mobile devices is huge and will continue to grow. Thus, supporting touch screens and mobile devices has been a priority since the birth of Mix. Touch interactions are as important to us as mouse and keyboard interactions.
This constraint may seem obvious, but for us it functioned as a catch-all. Predictable behavior included enforcing a single line of text (no line-breaks) and scrolling long text correctly. For example, a native text fields with overflowing text snaps back to the beginning of the string when keyboard/pointer focus leaves the field.
As mentioned previously, we needed our fluid text input to behave like an inline element. This led us to explore a span with a
contentEditable attribute. At first, an inline
contentEditable element seemed like a silver bullet because it dynamically resized based on content length. But once we considered the complications of line breaks and formatted content, the appeal quickly vanished.
contentEditable certainly was intriguing but not very practical.
We took a step back and remembered that native HTML text inputs strip formatting when you paste content. This was our breakthrough moment. We didn’t have to choose a native input over a span — we could use both. If our span mirrored the value of our text input and the text input sanitized the user’s input, we could experience the euphoria of an inline element without the
contentEditable hangover. Eureka!
The Mix web app is authored using React. This “mirrored value” solution is not unique to React, but React makes it easy to implement. Here’s the basic idea:
<input>, React triggers the
<input>becomes a state of our
valueis part of the component state, it can also be used elsewhere in the component.
<input>into the string inside a
<span>resizes fluidly based on content changes in the
In our final solution, the span acts as a spacer and the content inside is styled invisibly using CSS. As more characters are added to the input, the mirrored value inside the span pushes the search icon svg to the left and the clear icon svg to the right.
The above markup is nested inside a fieldset element. We used some crafty CSS to bring it all together.
<span>to flow “naturally” in the container.
text-align: centerfor the
<input>and set it to
<svg>clear icon to
z-index: 1to “float” above the
<input>. This allows the
<svg>clear icon to receive touch and pointer events.
The last piece of the puzzle was adding the “Search creators” placeholder. The process of rolling our own placeholder attribute was fairly straightforward: the value of the
<input> was “Search creators” until a user started typing. But there were a few wrinkles to iron out:
Preventing arrow key navigation was accomplished by intercepting (and discarding) the keypress events. To stop all the other unwanted behaviors, we needed to intercept taps/clicks and only allow the insertion cursor to start at the front of the placeholder text.
We implemented a mask using a
<div> and positioned it over the
<input> when the placeholder text was present. When a tap or click is intercepted by the mask, the cursor is placed at the front of the
setSelectionRange(0, 0). The mask is removed from the DOM when the user begins typing so that all normal touch and pointer behaviors are handled by the
If you dig into the the markup and styles on mix.fiftythree.com/search you’ll find the production implementation to be a bit more complex than what we’ve outlined here. For example, we have a request (loading) indicator that replaces the svg clear icon when waiting for an outstanding API request. This indicator and the clear icon share a container and that markup is not represented in the diagrams and discussion above.
Just before the holidays, we launched creator search in Paper and on mix.fiftythree.com, enabling user search by first name, last name and email address. From design to usability, each new Mix feature presents its own set of challenges. If you’re someone who’s passionate about building delightful interfaces for touch devices and the web, let us know. We’re always searching for great people.