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 framer-motion.
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 framer-motion a popular animation library for React.
Setup
We will install the required dependencies for the project.
yarn add framer-motion 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.
tailwind.config.js
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.
postcss.config.js
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.
styles/tailwind.css
@tailwind base;
@tailwind components;
@tailwind utilities;
Animating the Tabs
We will use the AnimatePresence
component from framer-motion 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.
data.ts
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.
Tab.tsx
'use client'
import { useState } from 'react'
import { cn} from 'lib/utils'
import { AnimatePresence, motion } from 'framer-motion'
interface TabProps {
title: string
content: string
}
export default function Tab({ contains, className }: { contains: TabProps[]; className?: string }) {
const [tab, setTab] = useState(contains[0])
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="tab-example-pointer"
className={cn(
'absolute inset-0 bottom-0 h-full w-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>
{/* content */}
<div className="border border-orange-300 px-4 py-5 dark:border-[0.5px]">
{/* <code className="h-[30vh] w-full overflow-y-auto">{tab.content}</code> */}
{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-[30vh] 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.
app/page.tsx
import { tabs } from '~/data'
import Tab from '~/components/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 framer-motion 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.