Mailchimp: Grow sales with Customer Journey Smarts
I’m thoroughly convinced that SVG unlocks a whole entire world of building interfaces on the web. It might seem daunting to learn SVG at first, but you have a spec that was designed to create shapes and yet, still has elements, like text, links, and aria labels available to you. You can accomplish some of the same effects in CSS, but it’s a little more particular to get positioning just right, especially across viewports and for responsive development.
What’s special about SVG is that all the positioning is based on a coordinate system, a little like the game Battleship. That means deciding where everything goes and how it’s drawn, as well as how it’s relative to each other, can be really straightforward to reason about. CSS positioning is for layout, which is great because you have things that correspond to one another in terms of the flow of the document. This otherwise positive trait is harder to work with if you’re making a component that’s very particular, with overlapping and precisely placed elements.
Truly, once you learn SVG, you can draw anything, and have it scale on any device. Even this very site uses SVG for custom UI elements, such as my avatar, above (meta!).
We won’t cover everything about SVGs in this post (you can learn some of those fundamentals here, here, here and here), but in order to illustrate the possibilities that SVG opens up for UI component development, let’s talk through one particular use case and break down how we would think about building something custom.
Recently, I was working on a project with my team at Netlify. We wanted to show the viewer which video in a series of videos in a course they were currently watching. In other words, we wanted to make some sort of thing that’s like a todo list, but shows overall progress as items are completed. (We made a free space-themed learning platform and it’s hella cool. Yes, I said hella.)
Here’s how that looks:
So how would we go about this? I’ll show an example in both Vue and React so that you can see how it might work in both frameworks.
We decided to make the platform in Next.js for dogfooding purposes (i.e. trying out our own Next on Netlify build plugin), but I’m more fluent in Vue so I wrote the initial prototype in Vue and ported it over to React.
Here is the full CodePen demo:
Let’s walk through this code a bit. First off, this is a single file component (SFC), so the template HTML, reactive script, and scoped styles are all encapsulated in this one file.
We’ll store some dummy tasks in data
, including whether each task is completed or not. We’ll also make a method we can call on a click directive so that we can toggle whether the state is done or not.
Now, what we want to do is create an SVG that has a flexible viewBox
depending on the amount of elements. We also want to tell screen readers that this a presentational element and that we will provide a title with a unique id of timeline
. (Get more information on creating accessible SVGs.)
The stroke
is set to currentColor
to allow for some flexibility — if we want to reuse the component in multiple places, it will inherit whatever color
is used on the encapsulating div.
Next, inside the SVG, we want to create a vertical line that’s the length of the task list. Lines are fairly straightforward. We have x1
and x2
values (where the line is plotted on the x-axis), and similarly, y1
and y2
.
The x-axis stays consistently at 10 because we’re drawing a line downward rather than left-to-right. We’ll store two numbers in data: the amount we want our spacing to be, which will be num1
, and the amount we want our margin to be, which will be num2
.
The y-axis starts with num2
, which is subtracted from the end, as well as the margin. The tasks.length
is multiplied by the spacing, which is num1
.
Now, we’ll need the circles that lie on the line. Each circle is an indicator for whether a task has been completed or not. We’ll need one circle for each task, so we’ll use v-for
with a unique key
, which is the index (and is safe to use here as they will never reorder). We’ll connect the click
directive with our method and pass in the index as a param as well.
CIrcles in SVG are made up of three attributes. The middle of the circle is plotted at cx
and cy,
and then we draw a radius with r.
Like the line, cx
starts at 10. The radius is 4 because that’s what’s readable at this scale. cy
will be spaced like the line: index times the spacing (num1
), plus the margin (num2
).
Finally, we’ll put use a ternary to set the fill
. If the task is done, it will be filled with currentColor
. If not, it will be filled with white
(or whatever the background is). This could be filled with a prop that gets passed in the background, for instance, where you have light and dark circles.
Finally, we are using CSS grid to align a div with the names of tasks. This is laid out much in the same way, where we’re looping through the tasks, and are also tied to that same click event to toggle the done state.
Here is where we ended up with the React version. We’re working towards open sourcing this so that you can see the full code and its history. Here are a few modifications:
Most of the other functionality is the same 🙂
You can see the final working version here:
This component is flexible enough to accommodate lists small and large, multiple browsers, and responsive sizing. It also allows the user to have better understanding of where they are in their progress in the course.
But this is just one component. You can make any number of UI elements: knobs, controls, progress indicators, loaders… the sky’s the limit. You can style them with CSS, or inline styles, you can have them update based on props, on context, on reactive data, the sky’s the limit! I hope this opens some doors on how you yourself can develop more engaging UI elements for the web.
React is the web’s most popular framework, always topping the charts for JavaScript developers awareness, interest, and satisfaction. Not to mention so many jobs listing it as a requirement these days. Frontend Masters has a the best courses on the web for React, including a complete learning course from the best teachers in JavaScript.
React is the web’s most popular framework, always topping the charts for JavaScript developers awareness, interest, and satisfaction. Not to mention so many jobs listing it as a requirement these days. Frontend Masters has a the best courses on the web for React, including a complete learning course from the best teachers in JavaScript.
Thank you, Sarah!
I have been using SVG for a quite while.
Here is what I think-
A better approach would be first design the Component using visual tool such as Adobe illustrator or inkscape then manipulate it or add interaction to it using JS.
This way it is more convenience.
Great article Sarah, really enjoyed and appreciate what it might have took for your team to do this.
@vishal: I’ve also been creating components with SVG for years and years, and you’re not wrong, that sometimes creating something in Illustrator is faster. However in this instance, you need the component to be flexible to many items and so you will need to dynamically create and bind lengths with JS, so that way is not flexible enough for a lot of use cases. You will also still need to write some of it by hand to make it accessibile. I want to be really clear that my team didn’t write this component, I did, so this isn’t just a writeup of someone else’s work, the article comes with an understanding of why I chose this approach as well. Cheers!