In 2021, you can visit a number of websites that will automatically generate a logo for you in a matter of minutes. That, of course, isn’t how we do things at Jotform.
We wanted to create a new identity for ourselves, using our own internal design team, based on how our product and users have evolved over the past 15 years. The process of creating a new brand for Jotform took dozens of team members within the company an entire year to complete.
With that, we’re excited to show you what we’ve been working on.
What’s changed?
Logo
We didn’t just update our logo, we overhauled it completely. First we created our own font to draw the logo, and then we introduced a completely new color scheme.
One of the first things you might notice is that we’ve lowercased the “f” in Jotform. This is now how it’ll appear not only in our branded logos but also whenever we refer to the company in writing. There were two significant reasons for this: 1) we felt the lower case “f” enhanced readability, and 2) most Jotform users already spelled our company name with a lowercase “f.”
Jotform’s pencil icon is a major part of our brand, and we felt it was important to keep it as a part of our new identity, with some needed improvements.
The icon is greatly simplified, without the fine lines and detail of the original version. The updated look is more modern and memorable. It also shows up better when shrunken for favicons and social media images, or printed on apparel.
The updated pencil is multicolored in order to demonstrate the many Jotform products and features that we’ve built in recent years. When arranged differently, the colors on the pencil can morph to represent form fields, the cells in a table, the bars on a bar graph, or the lines on a document.
One thing you’ll notice about our new design is circles, whether on our site pages or in the new logo itself. We used them because circles are flexible and expandable, just like Jotform. A circle is also a welcoming and soft shape, which gives our users a friendly experience when they’re navigating our site.
Tagline
We introduced a new tagline to accompany our new design: Powerful forms get it done.
We needed a tidy way to convey what Jotform has become and what it means to our users in 2021. We didn’t want our new messaging to focus solely on how easy it is to use our Form Builder; we also wanted the tagline to speak to the advancements we’ve made to our product over the past 15 years. Jotform has the most powerful forms anywhere, and that’s the focus of our messaging going forward.
Rebranding means changing hundreds of pages, both on our own site and across the web. Here’s a look at how some of the updates appear, next to their old versions:
Homepage
The bones of the homepage will remain the same, but we’ve livened it up with our new tagline, color scheme, and logo.
Form Builder
We’ve slightly changed the colors in our Form Builder navigation, with an emphasis on high contrast, while keeping the focus of the page on the form being created.
My Forms dashboard
Everything looks cleaner on the rebranded My Forms page. Jotform’s new navy blue extends across the header, and our new orange “Create Form” button really pops. The page is also easier to read and navigate.
What hasn’t changed?
While much has changed with Jotform, it’s still the same suite of products you know and love.
Our pricing plans are exactly the same, including our free Starter plan. It’s important for us to keep Jotform accessible to every type of organization, and we still offer all of our advanced features and integrations on our Starter plan.
We’re also keeping all the same features and products you know and love, including Jotform Tables, Jotform Mobile Forms, Jotform PDF Editor, and more.
And, even though we’ve given Jotform a fresh look, we’re still keeping Podo, our friendly mascot.
Our design process
You might have heard about Jotform’s famous hack weeks before. Every so often teams within Jotform will stop everything else they’re doing to collectively focus on a single goal. It’s how we’ve conceptualized many of our products. And it’s how we tackled creating a new brand for Jotform.
We actually developed this new brand identity over two separate hack weeks and came up with dozens of other concepts along the way. In the end, we felt like our new brand was the best representation of Jotform and its many features and users. But you can see how some of our other concepts inspired what ultimately became our new look.
Conclusion
Initiating a rebrand of Jotform meant reexamining what our company is today.
The previous version of our logo and brand was a reflection of how our users and employees saw the company at the time: easy-to-use, approachable, and friendly. It was important that we retained that in our new look, but the company has evolved over the years, and so have our users.
In the early days, Jotform served developers looking to create forms without the tedium that traditionally came with the process. As the years went by, DIY small businesses, nonprofits, and schools started using Jotform more and more because of its simplicity and the free plan.
But now we also count government entities, hospitals, Fortune 500 corporations, and major universities among those commonly using Jotform. In short, it’s a tool for everyone. This diversity of use cases needed to be reflected in the new Jotform.
We’re so excited to be able to share this new brand with you as we celebrate our 15th year in business and our 10 millionth user. We certainly couldn’t have done it without you.
For more information about the new look, visit the resources below:
In 2008, Pepsi hired the now-defunct Arnell Group to redesign its iconic red, white, and blue logo. The agency flattened and tilted Pepsi’s 3D globe to rest on its side, and replaced the bold font with lowercase, sans-serif text. The total price tag? Over a million dollars.
Seven figures may sound steep, but Pepsi is in good company. The BBC paid $1.8 million for a logo redesign back in 1997. And following a 2009 merger, the Australia and New Zealand Banking Group (ANZ) paid $15 million for a new logo and marketing campaign.
When I started Jotform in 2006, I didn’t know how to create a logo, so I bought one for $10 from an online design hub. It seemed like a great deal?—?and a good match for the product?—?until a customer alerted me that it was pulled directly from a Mac app.
We soon commissioned a second logo, which our own designers have gently nipped and tucked over the last 15 years. After that rocky start, I learned that good branding isn’t cheap. A sharp logo and tagline can elevate your business and your reputation. But, you don’t have to engage a pricey agency to have a memorable brand. In fact, dropping major cash doesn’t guarantee you’ll create the next swoosh, bitten apple, or golden arches.
Today, we’re revealing our first rebrand in over a decade?—?and I’m proud to say it was an inside job. Our team developed a fresh identity that not only looks fantastic (in my very biased opinion), but reinforces the essence of Jotform. It also strengthened my belief that the best ideas usually come from your own smart people.
Whether you’re just starting out with a tight grip on the budget, or you simply don’t want to engage a flashy agency, I’d like to take you inside our rebranding process and share the lessons we learned along the way.
Timing is everything
Before you dive in, re-evaluate whether you actually need to polish your branding, and whether the timing is right. How do you know? Every business is different, but I advise founders to wait until the market or your customers demand it. To be clear, terrible design won’t fly. You can’t compete with a sloppy or amateurish visual identity. But if everything is fine, don’t rush into a big rebranding project.
If, however, your business has shifted or your product is starting to show its age, it might be due for a makeover. At Jotform, we’ve always been hyper-focused on continuous improvement. Clean, engaging product design has always been our top priority, but the homepage, logo, and other marketing materials had some inconsistencies. We needed to bring everything up to the same standard.
Most importantly, the company has evolved. Our previous tagline was the “easy-to-use online form builder for every business.” Today, we provide much more than just forms. We have a powerful, multi-dimensional product that’s still easy to use, but that’s not the heart of our story. The rebrand needed to fix this narrative disconnect. And after many iterations, we landed on our new tagline: “powerful forms get it done.” It perfectly encapsulates who we are and what Jotform equips people to accomplish.
Know thyself
A successful rebrand requires an intimate understanding of who you are and where you want to go. Before you move a single pixel, ensure you can clearly articulate your mission and business value. Cut the jargony, corporate-speak and keep distilling until you could share it with a stranger on the bus. This excavation process takes time, and if you’re tackling the work internally, you might be tempted to skip it?—?don’t. You’ll save time, money, and avoid spinning your wheels by completing this crucial step.
Once you’ve clarified the vision, branding can be a way to literally design your future: What do you want to highlight? How do you want people to see you? Who are your peers? We’ve always aimed to make our product clean, colorful, powerful, and bold, so those traits led the way. We also wanted to show that we’re an innovative tech company alongside boundary-pushers like Google, Airtable, and monday.com. That inspired us to ensure our logo was similarly fresh and bright.
Nurture internal talent
If your company doesn’t have strong designers and writers, you might need to seek outside help. Earmark this as a goal and develop your capacity over time. Assuming you do have the talent, make the most of this incredible asset. After all, no one knows your culture, style, and preferences like your own team.
You might also think a rebrand is too big for employees with full-time responsibilities. In my experience, they’ll be excited to tackle such a creative and potentially meaningful project?—?as long as you give them enough time and space. Don’t just tack it on top of their day-to-day work. Free them up to do the necessary research, exploration, development, and refinement.
Our lead designer has been with us since 2015. We’ve collaborated closely ever since and she knows our product inside out. That created a shorthand that was invaluable as we spent the last year (yes, a full year) developing the new brand. We also held a series of design weeks, like hack weeks, where all of our product designers created new visual options. Eventually, we realized that we couldn’t cut the pencil from our logo. It symbolizes creativity and feels like an integral part of our identity.
Our team kept refining and we finally landed where we are today: a playful, stylized pencil built from the same colorful components that represent our forms. The logo has a sense of motion and power. It’s bold and confident, yet utterly simple. It also feels alive. We’re always moving forward, and so is our brand.
Take your time
The new brand might not be perfect, but it’s right for us. We know for sure, because it took hundreds of versions and 12 months to get here. And that’s one of the best reasons to tackle your own rebrand; you can set the pace. Don’t rush it, and don’t jump to finalize the first strong option. I’ve learned that creativity needs time to breathe. Today’s winning version might look all wrong in a few weeks or months.
I also recommend that you designate the final decision-maker(s). Who has the last word? Whether it’s the founder, CEO, lead designer, or a team vote, set your parameters upfront. Full transparency can prevent confusion, frustration, or hurt feelings. As always, I leaned on our team throughout this process. We thoroughly discussed and debated each choice, but when it came down to the wire, I made the final call. Thankfully, our staff have been nothing but supportive and excited. This is their company, too.
Getting here wasn’t always easy, but cultivating our own innovation was definitely the right call. It’s a healthy way to ensure the inside of your company matches the outside. I truly love Jotform’s new brand. I hope you do, too.
When I founded Jotform in 2006, I did so with the simple goal of making it easy to create and customize online forms. I remember how excited I was when our first user signed up!
So it’s remarkable to look back on the last 15 years and see how this brand has grown and how our 10 million users have helped shape the product you see today. Because Jotform is still the world’s easiest form builder, but we have become so much more than that.
Jotform has powerful forms that are limited only by your imagination. You can
Integrate them with hundreds of third-party services
Embed them anywhere online
Use them on any device
Automatically create PDFs and workflows through your submissions
Use conditional logic to change your forms based on the responses you get
Use Jotform Tables to organize your submission data and collaborate with others
Accept payments online
Protect your submission data with state-of-the-art security
In short, the possibilities are endless with our forms.
My goal with Jotform has always been to help your business run more efficiently; this process begins with our powerful forms and continues with our advanced features that allow you to manage and share data easily — all from one central platform.
That is why we’re rebranding Jotform with this vision:
Powerful forms get it done.
This is the simple truth behind our product and our mission; it’s what motivates us. Our forms are powerful, and we simply help you get things done. So whatever you need to accomplish — whether it’s reservations, applications, waivers, payments, registrations, surveys, patient intake forms, or anything else — Jotform is there from start to finish.
Fifteen years after founding Jotform, I couldn’t be more excited to share this defining vision with you. It felt fitting for our new brand design and logo to reflect the mature, versatile product we have become. (Be sure to check out this post for a deeper dive into our updated design.) I hope you enjoy our new look, but rest assured, our forms are still the same.
I want to thank all 10 million Jotform users — including small businesses, schools, healthcare organizations, and global corporations — for the trust they have put in our product. We are committed to delivering the same industry-leading product, features, and services for each and every one of you.Thank you for believing in Jotform, and remember, whatever your business needs, powerful forms get it done.
Not all browsers support all features. Say you want to write a fallback for browsers that doesn’t support CSS Grid. Not very common these days, but it’s just to illustrate a point.
You could write the supporting CSS in an @supports blocks:
Then to test the fallback, you quickly change @supports (display: grid) to something nonsense, like adding an “x” so it’s @supports (display: gridx). That’s a quick toggle:
The example above doesn’t have very good fallbacks does it?! Maybe I’d attempt to write something similar in flexbox, as hey, maybe there is some small group of browsers still out there that support flexbox and not grid. More likely, I’d just write a fallback that makes things look pretty OK as a column.
If I’m fairly confident the browser supports @supports queries (oh, the irony), I could write it like:
@supports (display: grid) {
/* grid stuff */
}
@supports not (display: grid) {
/* at least space them out a bit */
.block { margin: 10px }
}
That’s an assumption that will get safer and safer to make, and honestly, we’re probably already there (if you’ve dropped IE support).
This makes me want that @when syntax even more though, because then we could write:
Design trends on top of design trends. This theme of this month’s collection is trends that seem to build on each other. These examples use multiple trends listed here: hero typography, round buttons, and big branding.
Here’s what’s trending in design this month…
1. Hero Typography
Big, bold, and even unusual typography choices are the norm right now for hero headers in website design. The thread in this design trend is that type options seem to break all the rules – and it doesn’t matter.
These hero typography styles are often dramatically oversized, use unusual or nontraditional type styles, and break at least one common rule of typography. The trick is to do these things while creating a visual that still works.
For the most part, that means the typographic element is the dominant art, although not always. The examples below each take a different approach and can give you an idea if you love this website design trend or not.
Eighty uses oversized type elements with almost nothing else above the fold. The rule-breaking happens on the fourth line of text with a scrolling series of serif words. The two typefaces don’t seem to match and have a stark contrast. There’s also the sneaky registered trademark icon that’s spinning next to the brand name. (Another trend – big branding – that we dive into more below.)
Miranda Biondi uses super large text to grab attention – and a lot of it. The design also sneaks the contact and social media links in an unusual location, creating an odd text wrap that pushes the image. You can see the broken “rules” there. Overall, it is very attention-getting but a little difficult to read.
Humain’s homepage is rooted in a font choice that’s pretty unexpected. The all-caps serif is thin and complex. It’s not exceptionally easy to read, although it is beautiful. There’s a second level of hidden text that you can discover with hover and the brighter sphere.
2. Round Buttons
Buttons have been mostly rectangular for a while. Some have hints of rounded edges, but nothing as distinct as the circular buttons that are growing in popularity.
Round buttons are having a moment from major call to action click elements, to timeline navigation or secondary actions.
What’s nice about this trend is that simply the change from a rectangle to a circle is enough to make you look at the element because it is different from what you might expect. The challenge is ensuring that users understand the interactive quality of circles in these instances.
When using a nontraditional element such as this, it is important to include common cues so that users know what to do with round buttons. This might include tooltips, hover actions, shadows, or tiny animations that draw users to the designs.
Salesgroup uses small hover animations on the circular buttons. It further emphasizes it with a circlular button for the cookie notice that pops up on the screen.
Jan Jansen uses a big circular button, the only thing to click on the screen, and a hover state to imply functionality.
Earth Eclipsed uses a series of different circular click elements to facilitate understanding. Sometimes just the lack of another button style is enough to show that circles are for clicking.
3. Big Branding
After a long time of subtle, rather small corner branding for websites, big branding is in.
This design trend features logos – most commonly logotypes – that are almost uncomfortably large on the homepage. They can be in the traditional top-left location or almost anywhere on the screen.
The trick is to integrate branding with the rest of the design not to feel garish. This can be rather difficult to pull off and seems to be one of those things that people either love or hate when they see it.
Here’s how three different websites are doing it:
The 50th anniversary logo is a timed solution with big branding. It creates emphasis on the historical aspect of the train. Not only does the logo appear large on the homepage, but there’s also a loading animation as well.
Kunst Architects Associated uses a very large brand representation in the middle of the hero slider. The giant type element brings your eye into the design for sure and is re-emphasized by the company name in the left sidebar. The trick here is the balance between brand and other information in that valuable homepage space.
Hyer might use one of the biggest corner logotypes you’ll find. There’s no second-guessing what website you are on. The longer-term question is, does the big lettering imprint more on your memory so that you come back to the website later when you need the products or services offered? That’s a hard question to answer, but one that might be worth debate for design teams considering a visual outline such as this one.
Conclusion
There’s a risk when it comes to layering trends in a single design. If they don’t take off, the design can look dated fast, and there’s a lot of work to remove multiple trendy visuals from the project.
But when trends take off, they can work wonders. So it will be interesting to look back in a few months and see which of these trends is still making waves.
Animating elements with CSS can either be quite easy or quite difficult depending on what you are trying to do. Changing the background color of a button when you hover over it? Easy. Animating the position and size of an element in a performant way that also affects the position of other elements? Tricky! That’s exactly what we’ll get into here in this article.
A common example is removing an item from a stack of items. The items stacked on top need to fall downwards to account for the space of an item removed from the bottom of the stack. That is how things behave in real life, and users may expect this kind of life-like motion on a website. When it doesn’t happen, it’s possible the user is confused or momentarily disorientated. You expect something to behave one way based on life experience and get something completely different, and users may need extra time to process the unrealistic movement.
Here is a demonstration of a UI for adding items (click the button) or removing items (click the item).
CodePen Embed Fallback
You could paper over the poor UI slightly by adding a “fade out” animation or something, but the result won’t be that great, as the list will will abruptly collapse and cause those same cognitive issues.
Applying CSS-only animations to a dynamic DOM event (adding brand new elements and fully removing elements) is extremely tricky work. We’re going to face this problem head-on and go over three very different types of animations that handle this, all accomplishing the same goal of helping users understand changes to a list of items. By the time we’re done, you’ll be armed to use these animations, or build your own based on the concepts.
We will also touch upon accessibility and how elaborate HTML layouts can still retain some compatibility with accessibility devices with the help of ARIA attributes.
The Slide-Down Opacity Animation
A very modern approach (and my personal favorite) is when newly-added elements fade-and-float into position vertically depending on where they are going to end up. This also means the list needs to “open up” a spot (also animated) to make room for it. If an element is leaving the list, the spot it took up needs to contract.
Because we have so many different things going on at the same time, we need to change our DOM structure to wrap each .list-item in a container class appropriately titled .list-container. This is absolutely essential in order to get our animation to work.
Now, the styling for this is unorthodox because, in order to get our animation effect to work later on, we need to style our list in a very specific way that gets the job done at the expense of sacrificing some customary CSS practices.
First, we’re using margin-top to create vertical space between the elements in the stack. There’s no margin on the bottom so that the other list items can fill the gap created by removing a list item. That way, it still has margin on the bottom even though we have set the container height to zero. That extra space is created between the list item that used to be directly below the deleted list item. And that same list item should move up in reaction to the deleted list item’s container having zero height. And because this extra space expands the vertical gap between the list items further then we want it to. So that’s why we use margin-top — to prevent that from happening.
But we only do this if the item container in question isn’t the first one in the list. That’s we used :not(:first-child) — it targets all of the containers except the very first one (an enabling selector). We do this because we don’t want the very first list item to be pushed down from the top edge of the list. We only want this to happen to every subsequent item thereafter instead because they are positioned directly below another list item whereas the first one isn’t.
Now, this is unlikely to make complete sense because we are not setting any elements to zero height at the moment. But we will later on, and in order to get the vertical spacing between the list elements correct, we need to set the margin like we do.
A note about positioning
Something else that is worth pointing out is the fact that the .list-item elements nested inside of the parent .list-container elements are set to have a position of absolute, meaning that they are positioned outside of the DOM and in relation to their relatively-positioned .list-container elements. We do this so that we can get the .list-item element to float upwards when removed, and at the same time, get the other .list-item elements to move and fill the gap that removing this .list-item element has left. When this happens, the .list-container element, which isn’t positioned absolute and is therefore affected by the DOM, collapses its height allowing the other .list-container elements to fill its place, and the .list-item element — which is positioned with absolute — floats upwards, but doesn’t affect the structure of the list as it isn’t affected by the DOM.
Handling height
Unfortunately, we haven’t yet done enough to get a proper list where the individual list-items are stacked one by one on top of each other. Instead, all we will be able to see at the moment is just a single .list-item that represents all of the list items piled on top of each other in the exact same place. That’s because, although the .list-item elements may have some height via their padding property, their parent elements do not, but have a height of zero instead. This means that we don’t have anything in the DOM that is actually separating these elements out from each other because in order to do that, we would need our .list-item containers to have some height because, unlike their child element, they are affected by the DOM.
To get the height of our list containers to perfectly match the height of their child elements, we need to use JavaScript. So, we store all of our list items within a variable. Then, we create a function that is called immediately as soon as the script is loaded.
This becomes the function that handles the height of the list container elements:
const listItems = document.querySelectorAll('.list-item');
function calculateHeightOfListContainer(){
};
calculateHeightOfListContainer();
The first thing that we do is extract the very first .list-item element from the list. We can do this because they are all the same size, so it doesn’t matter which one we use. Once we have access to it, we store its height, in pixels, via the element’s clientHeight property. After this, we create a new element that is prepended to the document’s body immediately after so that we can directly create a CSS class that incorporates the height value we just extracted. And with this element safely in the DOM, we write a new .list-container class with styles that automatically have priority over the styles declared in the external stylesheet since these styles come from an actual tag. That gives the .list-container classes the same height as their .list-item children.
Right now, our list looks a little drab — the same as the what we saw in the first example, just without any of the addition or removal logic, and styled in a completely different way to the list constructed from
and tags list that were used in that opening example.
We’re going to do something now that may seem inexplicable at the moment and modify our .list-container and .list-item classes. We’re also creating extra styling for both of these classes that will only be added to them if a new class, .show, is used in conjunction with both of these classes separately.
The purpose we’re doing this is to create two states for both the .list-container and the .list-item elements. One state is without the .show classes on both of these elements, and this state represents the elements as they are animated out from the list. The other state contains the .show class added to both of these elements. It represents the specified .list-item as firmly instantiated and visible in the list.
In just a bit, we will switch between these two states by adding/removing the .show class from both the parent and the container of a specific .list-item. We’ll combined that with a CSS transition between these two states.
Notice that combining the .list-item class with the .show class introduces some extra styles to things. Specifically, we’re introducing the animation that we are creating where the list item fades downwards and into visibility when it is added to the list — the opposite happens when it is removed. Since the most performant way to animate elements positions is with the transform property, that is what we will use here, applying opacity along the way to handle the visibility part. Because we already applied a transition property on both the .list-item and the .list-container elements, a transition automatically takes place whenever we add or remove the .show class to both of these elements due to the extra properties that the .show class brings, causing a transition whenever we either add or remove these new properties.
In response to the .show class, we are going back to our JavaScript file and changing our only function so that the .list-container element are only given a height property if the element in question also has a .show class on it as well, Plus, we are applying a transition property to our standard .list-container elements, and we will do it in a setTimeout function. If we didn’t, then our containers would animate on the initial page load when the script is loaded, and the heights are applied the first time, which isn’t something we want to happen.
Now, if we go back and view the markup in DevTools, then we should be able to see that the list has disappeared and all that is left is the button. The list hasn’t disappeared because these elements have been removed from the DOM; it has disappeared because of the .show class which is now a required class that must be added to both the .list-item and the .list-container elements in order for us to be able to view them.
The way to get the list back is very simple. We add the .show class to all of our .list-container elements as well as the .list-item elements contained inside. And once this is done we should be able to see our pre-created list items back in their usual place.
We won’t be able to interact with anything yet though because to do that — we need to add more to our JavaScript file.
The first thing that we will do after our initial function is declare references to both the button that we click to add a new list item, and the .list element itself, which is the element that wraps around every single .list-item and its container. Then we select every single .list-container element nested inside of the parent .list element and loop through them all with the forEach method. We assign a method in this callback, removeListItem, to the onclick event handler of each .list-container. By the end of the loop, every single .list-container instantiated to the DOM on a new page load calls this same method whenever they are clicked.
Once this is done, we assign a method to the onclick event handler for addBtn so that we can activate code when we click on it. But obviously, we won’t create that code just yet. For now, we are merely logging something to the console for testing.
Starting work on the onclick event handler for addBtn, the first thing that we want to do is create two new elements: container and listItem. Both elements represent the .list-item element and their respective .list-container element, which is why we assign those exact classes to them as soon as we create the them.
Once these two elements are prepared, we use the append method on the container to insert the listItem inside of it as a child, the same as how these elements that are already in the list are formatted. With the listItem successfully appended as a child to the container, we can move the container element along with its child listItem element to the DOM with the insertBefore method. We do this because we want new items to appear at the bottom of the list but before the addBtn, which needs to stay at the very bottom of the list. So, by using the parentNode attribute of addBtn to target its parent, list, we are saying that we want to insert the element as a child of list, and the child that we are inserting (container) will be inserted before the child that is already on the DOM and that we have targeted with the second argument of the insertBefore method, addBtn.
Finally, with the .list-item and its container successfully added to the DOM, we can set the container’s onclick event handler to match the same method as every other .list-item already on the DOM by default.
If we try this out, then we won’t be able to see any changes to our list no matter how many times we click the addBtn. This isn’t an error with the click event handler. Things are working exactly how they should be. The .list-item elements (and their containers) are added to the list in the correct place, it is just that they are getting added without the .show class. As a result, they don’t have any height to them, which is why we can’t see them and is why it looks like nothing is happening to the list.
To get each newly added .list-item to animate into the list whenever we click on the addBtn, we need to apply the .show class to both the .list-item and its container, just as we had to do to view the list items already hard-coded into the DOM.
The problem is that we cannot just add the .show class to these elements instantly. If we did, the new .list-item statically pops into existence at the bottom of the list without any animation. We need to register a few styles before the animation additional styles that override those initial styles for an element to know what transition to make. Meaning, that if we just apply the .show class to are already in place — so no transition.
The solution is to apply the .show classes in a setTimeout callback, delaying the activation of the callback by 15 milliseconds, or 1.5/100th of a second. This imperceptible delay is long enough to create a transition from the proviso state to the new state that is created by adding the .show class. But that delay is also short enough that we will never know that there was a delay in the first place.
Success! It is now time to handle how we remove list items when they are clicked.
Removing list items shouldn’t be too hard now because we have already gone through the difficult task of adding them. First, we need to make sure that the element we are dealing with is the .list-container element instead of the .list-item element. Due to event propagation, it is likely that the target that triggered this click event was the .list-item element.
Since we want to deal with the associated .list-container element instead of the actual .list-item element that triggered the event, we’re using a while-loop to loop one ancestor upwards until the element held in container is the .list-container element. We know it works when container gets the .list-container class, which is something that we can discover by using the contains method on the classList property of the container element.
Once we have access to the container, we promptly remove the .show class from both the container and its .list-item once we have access to that as well.
function removeListItem(e) {
let container = e.target;
while (!container.classList.contains('list-container')) {
container = container.parentElement;
}
container.classList.remove('show');
const listItem = container.querySelector('.list-item');
listItem.classList.remove('show');
}
And here is the finished result:
CodePen Embed Fallback
Accessibility & Performance
Now you may be tempted to just leave the project here because both list additions and removals should now be working. But it is important to keep in mind that this functionality is only surface level and there are definitely some touch ups that need to be made in order to make this a complete package.
First of all, just because the removed elements have faded upwards and out of existence and the list has contracted to fill the gap that it has left behind does not mean that the removed element has been removed from the DOM. In fact, it hasn’t. Which is a performance liability because it means that we have elements in the DOM that serve no purpose other than to just accumulate in the background and slow down our application.
To solve this, we use the ontransitionend method on the container element to remove it from the DOM but only when the transition caused by us removing the .show class has finished so that its removal couldn’t possibly interrupt our transition.
function removeListItem(e) {
let container = e.target;
while (!container.classList.contains('list-container')) {
container = container.parentElement;
}
container.classList.remove('show');
const listItem = container.querySelector('.list-item');
listItem.classList.remove('show');
container.ontransitionend = function(){
container.remove();
}
}
We shouldn’t be able to see any difference at this point because allwe did was improve the performance — no styling updates.
The other difference is also unnoticeable, but super important: compatibility. Because we have used the correct
and tags, devices should have no problem with correctly interpreting what we have created as an unordered list.
Other considerations for this technique
A problem that we do have however, is that devices may have a problem with the dynamic nature of our list, like how the list can change its size and the number of items that it holds. A new list item will be completely ignored and removed list items will be read as if they still exist.
So, in order to get devices to re-interpret our list whenever the size of it changes, we need to use ARIA attributes. They help get our nonstandard HTML list to be recognized as such by compatibility devices. That said, they are not a guaranteed solution here because they are never as good for compatibility as a native tag. Take the
tag as an example — no need to worry about that because we were able to use the native unordered list element.
We can use the aria-live attribute to the .list element. Everything nested inside of a section of the DOM marked with aria-live becomes responsive. In other words, changes made to an element with aria-live is recognized, allowing them to issue an updated response. In our case, we want things highly reactive and we do that be setting the aria live attribute to assertive. That way, whenever a change is detected, it will do so, interrupting whatever task it was currently doing at the time to immediately comment on the change that was made.
This is a more subtle animation where, instead of list items floating either up or down while changing opacity, elements instead just collapse or expand outwards as they gradually fade in or out; meanwhile, the rest of the list repositions itself to the transition taking place.
The cool thing about the list (and perhaps some remission for the verbose DOM structure we created), would be the fact that we can change the animation very easily without interfering with the main effect.
So, to achieve this effect, we start of by hiding overflow on our .list-container. We do this so that when the .list-container collapses in on itself, it does so without the child .list-item flowing beyond the list container’s boundaries as it shrinks. Apart from that, the only other thing that we need to do is remove the transform property from the .list-item with the .show class since we don’t want the .list-item to float upwards anymore.
This last animation technique is strikingly different fromithe others in that the container animation and the .list-item animation are actually out of sync. The .list-item is sliding to the right when it is removed from the list, and sliding in from the right when it is added to the list. There needs to be enough vertical room in the list to make way for a new .list-item before it even begins animating into the list, and vice versa for the removal.
As for the styling, it’s very much like the Slide Down Opacity animation, only thing that the transition for the .list-item should be on the x-axis now instead of the y-axis.
As for the onclick event handler of the addBtn in our JavaScript, we’re using a nested setTimeout method to delay the beginning of the listItem animation by 350 milliseconds after its container element has already started transitioning.
In the removeListItem function, we remove the list item’s .show class first so it can begin transitioning immediately. The parent container element then loses its .show class, but only 350 milliseconds after the initial listItem transition has already started. Then, 600 milliseconds after the container element starts to transition (or 950 milliseconds after the listItem transition), we remove the container element from the DOM because, by this point, both the listItem and the container transitions should have come to an end.
There you have it, three different methods for animating items that are added and removed from a stack. I hope that with these examples you are now confident to work in a situation where the DOM structure settles into a new position in reaction to an element that has either been added or removed from the DOM.
As you can see, there’s a lot of moving parts and things to consider. We started with that we expect from this type of movement in the real world and considered what happens to a group of elements when one of them is updated. It took a little balancing to transition between the showing and hiding states and which elements get them at specific times, but we got there. We even went so far as to make sure our list is both performant and accessible, things that we’d definitely need to handle on a real project.
Anyway, I wish you all the best in your future projects. And that’s all from me. Over and out.
Dave and I slapped up a little videos section of the ShopTalk website. Twelve so far! They are short-ish, between 10-20 minutes, each focused on one fairly specific thing. We’re kinda just dipping our toes here — we don’t even have a real proper name for them yet! The place to subscribe to them is YouTube, and you might actually be subscribed already as we’ve been publishing them right to the CSS-Tricks YouTube Channel. There is a direct RSS feed as well if you’re cool like that.
One nice by-product of exploring video is that we get a chance to re-explain mouth-coding examples or overly visual concepts that were probably confusing on the audio podcast. As much as I love podcasting, the lack of visual examples for a visual field like Web Design and Development is a limitation. I like that the YouTube series is like supplementary material to ideas covered in the podcast, rather than a replacement.
Quick hits:
If you have topic ideas you’d like to see, hit me in the comments or anywhere else.
If you have ideas on how to make the show work, also let me know (E.g. Is the quality OK? Is the length OK? Are the thumbnails OK? What else can we do to appease the YouTube Algorithm Gods?)
Every day design fans submit incredible industry stories to our sister-site, Webdesigner News. Our colleagues sift through it, selecting the very best stories from the design, UX, tech, and development worlds and posting them live on the site.
The best way to keep up with the most important stories for web professionals is to subscribe to Webdesigner News or check out the site regularly. However, in case you missed a day this week, here’s a handy compilation of the top curated stories from the last seven days. Enjoy!
How To Use The Vite Build Tool with React — Vite is hot, in part, because it’s based on esbuild and wickedly fast. It’s from Evan You of Vue fame, but it’s not a Vue-specific tool. Here, NARUHODO covers how to configure it to work with React.
React Architecture: How to Structure and Organize a React Application — Tania Rascia with “an opinionated guide” on project structure. Looks pretty nice to me. I like the @ import aliases. Looks like it would support a monorepo-type environment pretty well. I also like the distinction between global vs. resuable components (called just “components” here) and views vs. pages. I’d probably separate into three: Library Components (no global state, no queries/mutations, more design-y and intentionally reusable), Project Components (business logic, global state, not very reuable), and Pages (routing concerned).
What’s NOT new in React 18 — Benny Powers is a little salty about React’s lack of support. I agree it’s unfortunate, as web components do some things really well and React does some things really well and it would be nice to see them make buddies.
How React got Traction — A bit of irony when considering the above link… Shawn Wang and Pete Hunt talk on this podcast about the history of React and how it came to be so popular: “How React overcame its haters: by listening.”
Compound Components In React — Ichoku Chinonso covers this super useful pattern. Some components are built from a bucket of other little components (think Tabs, TabBar, Tab, TabPanels, TabPanel) and, with the Compound Component model, you get more flexibility, logical importing, and usage of the whole lot. I’m curious about the origins of this pattern. I know Ryan Florence was talking about it in 2017 because I first saw Kent Dodds pointing to it. Googlin’ around, there are loads of random articles about it. Maybe it comes from deeper computer science concepts?
The Perils of Rehydration — Josh Comeau covers a bug that I’ve had to fight against multiple times in the last few weeks: React looking like it’s completely pooping the bed on constructing the DOM. Like elements that are clearly nested properly in the JSX appearing in parent elements, or like you’ve forgotten to close half your dang HTML elements and the browser is majorly confused. The problem comes from trying to do server side rendering (SSR) and client side rendering (CSR), which confuses the rehydration. The DOM from the SSR doesn’t match when CSR takes over. Fortunately, there is some fairly straightforward trickery to fix it.
While I’m a front-end developer at heart, I’ve rarely had the luxury of focusing on it full time. I’ve been dipping in and out of JavaScript, never fully caught up, always trying to navigate the ecosystem all over again each time a project came up. And framework fatigue is real!
So, instead of finally getting into Rollup to replace an ancient Browserify build on one of our codebases (which could also really use that upgrade from Polymer to LitElement…), I decided to go “stackless”.
I’m certainly not dogmatic about it, but I think if you can pull of a project with literally zero build process. It feels good while working on it and feels very good when you come back to it months/years later. Plus you just pick up and go.
Imports, yo — they go a long way.
Native support for modularity is the most important step towards a build-free codebase. If I had access to only one ES6 feature for the rest of my life, I’m confident that modules would take me most of the way there when it comes to well-structured native JavaScript.
That last sentence in the post is a stinger. I’d say we’re not far off.