Track: The Best Layout Component That You’ve Probably Never Heard Of
I’m helping to build a design system for a client, and a colleague of mine (Matt Stow) introduced me to an interesting component that he created, which has fast become one of my most used layout components, so I thought I’d write about it.
“Track” is a layout component for distributing content horizontally. It has two “rails” (one on each end) and a flexible “center”. Once you start using this component, you realise you can use it everywhere. A checkbox with an inline label is a Track. A user avatar with your name next to it — that’s a Track. Anything with an icon and some corresponding text is also a Track. I’m sure you get the idea.
The rails each have flex-shrink: 0
applied to them so that things like icons and images can’t get squished when there isn’t enough space. The center has flex-grow: 1
to take up the remaining available space, as well as min-width: 0px
to prevent horizontal overflow and ensure that text truncation behaves the way you’d expect.
We expose a gap
prop for controlling spacing between the rails and the content, and a verticalAlign
prop for aligning content to the top, middle, or bottom. At least, that’s what it used to do. We just added some new options to this prop to make it even more powerful!
Let’s say you’re displaying an address on a website, and you want to put an icon at the start to make it more scannable and visually interesting. Here’s what that markup might look like:
<Track
railStart={<MapPinIcon />}
center={<Text>42 Wallaby Way, Sydney</Text>}
gap="4"
verticalAlign="middle"
/>
Nice, that looks great. But what happens if that address is dynamic? Well, now you have to handle edge cases. If a user has an address like: Unit 456, Building 789, Street 1234, Complex XYZ, Block A, Level 12, Wing C, Suite 345, Lot 678, Road 9012, Estate UVW, Sydney, well, that’s probably not going to fit on one line. We’ve told the icon to align to the middle, so now instead of the icon lining up with the text, it’s floating somewhere in the middle, and it looks kinda weird. You could try verticalAlign="top"
, but if the icon’s height is different from the text, it’s still going to be misaligned. So, how do you fix this?
Well, inspired by this tweet from Adam Wathan, the secret is to use a zero-width space. We updated the verticalAlign
prop to also accept typography tokens. In that case, we add a zero-width space alongside the rail content, apply display: flex
and align-items: center
to the element that wraps the rail content, and align-items: flex-start
to the track itself. Now, the icon is centred with the first line of text, and things wrap without issue.