Today, let's explore how to recreate one of Linear's captivating hero section animations: the staggered text animation.
Setting up a Vite React app with Tailwind CSS
First, we create a Vite React app using the command **npx create vite app**
, selecting React as the library. Follow the official Tailwind CSS documentation to set up Tailwind in the project. It involves six straightforward steps.
Start the development server with **npm run dev**
. You should see your app running on **localhost:5173**
.
You can choose to use Next.js or Remix as alternatives to Vite.
Generating the markup
The default markup in a Vite React app is a far cry from Linear's hero section and hand coding will take a lot of time.
Thankfully, we have AI to get us 80% of the way there without all that work.
Starting with this mockup in Figma, I used the Builder.io Figma plugin to convert the design into React + Tailwind code using Visual Copilot.
Simply click Generate in Figma, then copy and paste the generated code into your codebase.
I placed it in a new file named Hero.tsx.
Adding the slide-in animation
To enhance Tailwind's animation capabilities, modify theme.extend.animation
and theme.extend.keyframes
in the tailwind.config.js
file:
export default { content: ["./index.html", "./src/*/.{js,ts,jsx,tsx}"], theme: { extend: { keyframes: { slidein: { from: { opacity: "0", transform: "translateY(-10px)", }, to: { opacity: "1", transform: "translateY(0)", }, }, }, animation: { slidein: "slidein 1s ease 300ms", }, }, }, plugins: [], };
This code snippet defines a new slidein
animation. The from
keyframe starts with the content at 0% opacity and slightly above its final position, while the to
keyframe completes the animation at 100% opacity and its final position.
The animation lasts 1 second with an ‘ease’ timing-function and a 300ms delay.
Apply this animation to each of the four elements representing the hero text in Hero.tsx
:
Linear is a better way
to build products
Meet the new standard for modern software development.
Streamline issues, sprints, and product roadmaps.
The animation runs but all the elements slide in at once. To create a staggered effect, we introduce different delays for each element by defining four variants of the **slidein**
animation in Tailwind's configuration:
animation: { slidein300: "slidein 1s ease 300ms", slidein500: "slidein 1s ease 500ms", slidein700: "slidein 1s ease 700ms", },
Update the Hero component's classNames
to reflect these new animation variants:
Linear is a better way
to build products
Meet the new standard for modern software development.
Streamline issues, sprints, and product roadmaps.
This introduces code duplication, but we'll address that shortly.
Now, our animations stagger beautifully, but there's an issue: the elements are visible before the animation starts. To fix this, add an **opacity-0**
class to ensure they're hidden initially:
Linear is a better way
to build products
Meet the new standard for modern software development.
Streamline issues, sprints, and product roadmaps.
The staggered animation works perfectly. However, post-animation, the hero text elements all disappear. To fix this, we specify [**animation-fill-mode: forwards**](https://developer.mozilla.org/en-US/docs/Web/CSS/animation-fill-mode)
so the elements maintain their final keyframe styles:
animation: { slidein300: "slidein 1s ease 300ms forwards", slidein500: "slidein 1s ease 500ms forwards", slidein700: "slidein 1s ease 700ms forwards", },
Our animations stagger beautifully as expected.
Refactoring with CSS variables for delay
To optimize our code, let's refactor our custom animations using CSS variables. We introduce a --slidein-delay
variable with a default value of 0ms
:
animation: { slidein: "slidein 1s ease var(--slidein-delay, 0) forwards", }
We then apply this variable to our Hero component:
Linear is a better way
to build products
Meet the new standard for modern software development.
Streamline issues, sprints, and product roadmaps.
And there you have it — a sleek staggered text animation similar to Linear's landing page, achieved using React and Tailwind CSS.