
Tab Animation with framer motion
A simple tab animation with framer motion
## Requirements
Tabs are a common UI element that can be used to switch between different views. In this post, we will create a simple tab animation with motion/react.
This post assumes that you have a basic understanding of React. If you are new to React, you can follow the React getting started guide. We will also use tailwindcss for styling and motion/react a popular animation library for React.
## Setup
We will install the required dependencies for the project.
npm install motion/react tailwindcss postcss autoprefixer clsx
pnpm add motion/react tailwindcss postcss autoprefixer clsx
yarn add motion/react tailwindcss postcss autoprefixer clsx
bun add motion/react tailwindcss postcss autoprefixer clsx
## Styling the Tabs
We will use tailwindcss to style the tabs. We will create a new file tailwind.config.js
in the root of the project and add the following code.
module.exports = {
experimental: {
optimizeUniversalDefaults: true
},
content: ['./src/**/*.{js,jsx,ts,tsx,vue,mdx,md}'],
darkMode: 'class',
theme: {
extend: {}
},
plugins: []
};
We will also create a new file postcss.config.js
in the root of the project and add the following code.
module.exports = {
plugins: {
'tailwindcss/nesting': {}, // enable css nesting
tailwindcss: {},
autoprefixer: {}
}
};
We will also update the tailwind.css
file in the styles
folder with the following code.
@tailwind base;
@tailwind components;
@tailwind utilities;
## Animating the Tabs
We will use the AnimatePresence
component from motion/react to animate the tabs. We will also use the motion
component to animate the tab pointer.
## Creating the Tabs
### Data for the components
We will create a simple array that will hold the tab data for the component. The data will contain the tab title and content.
export const tabs = [
{
title: 'Frontend',
content: 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Harum voluptas ducimus.'
},
{
title: 'Backend',
content: 'Lorem ipsum dolor sit amet consectetur adipisicing elit.'
}
];
export const tabs = [{
title: "Frontend",
content: "Lorem ipsum dolor sit amet consectetur adipisicing elit. Harum voluptas ducimus."
}, {
title: "Backend",
content: "Lorem ipsum dolor sit amet consectetur adipisicing elit."
}];
### Tab component
A new file Tab.tsx
will be created in the components
folder. This component will take the tab data as props and render the tab title and content.
'use client';
import { useId, useState } from 'react';
import { AnimatePresence, motion } from 'motion/react';
import { cn } from 'lib/utils';
interface TabProps {
title: string;
content: string;
}
export default function Tab({ contains, className }: { contains: TabProps[]; className?: string }) {
const [tab, setTab] = useState(contains[0]);
const animationId = useId();
return (
<div className={cn('my-5', className)}>
<div className="space-y-2">
{/* menu items */}
<div className="max-xsm:text-sm flex w-full items-center space-x-4 overflow-x-auto border border-orange-300 dark:border-[0.5px]">
{contains.map((item, idx) => (
<button key={idx} className={cn('relative')} onClick={() => setTab(item)}>
<AnimatePresence>
{tab.title === item.title && (
<motion.div
layoutId={animationId}
className={cn(
'absolute inset-0 size-full bg-orange-300/50 backdrop-blur',
idx === 0 && 'rounded-l-sm',
idx === contains.length - 1 && 'rounded-r-sm'
)}
/>
)}
</AnimatePresence>
<div className={cn('relative z-[1] flex items-center space-x-2 px-3 py-1 font-light uppercase')}>
{/* <item.icon className="h-4 w-auto" /> */}
<span>{item.title}</span>
</div>
</button>
))}
</div>
<div className="border border-orange-300 px-4 py-5 dark:border-[0.5px]">
{contains.map(
(item, idx) =>
item.content === tab.content && (
<AnimatePresence key={idx}>
<motion.div
initial={{ y: 50, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
exit={{ y: 50, opacity: 0 }}
transition={{
type: 'spring',
duration: 1,
delay: 0.25,
stiffness: 260,
damping: 20
}}
className="h-[10vh] w-full overflow-y-auto"
>
{item.content}
</motion.div>
</AnimatePresence>
)
)}
</div>
</div>
</div>
);
}
### Using the Tab component
We will import the Tab.tsx
component into your component or page example app/page.tsx
file and pass the tabs
data as props.
import { tabs } from '~/data';
import Tab from '~/components/animated-tab';
export default function Home() {
return (
<div className="mx-auto max-w-2xl">
<Tab contains={tabs} />
</div>
);
}
import { tabs } from "~/data";
import Tab from "~/components/animated-tab";
export default function Home() {
return <div className="mx-auto max-w-2xl">
<Tab contains={tabs} />
</div>;
}
## Conclusion
We have successfully created a tab component with motion/react and tailwindcss. Which can be used in any project to display content in a tabbed format. Our tab component is also responsive and can be used on any device. Resulting in a better user experience. Below is the result of the tab component we created.
Published on April 15, 2023
3 min read
Found an Issue!
Find an issue with this post? Think you could clarify, update or add something? All my posts are available to edit on Github. Any fix, little or small, is appreciated!
Edit on GitHub