Tailwind CSS Transition Delay
Transition delay defines how long a transition should wait before it begins. When crafting user experiences and animations, transition delay adds subtle elegance and control over the timing of transitions. Tailwind CSS provides preconfigured utilities and customization options for the transition-delay
property, making it efficient and easy to apply.
In this guide, we'll explore various ways to use and customize transition delays with Tailwind CSS, including conditional applications, responsiveness, and custom values.
Class | Properties | Example |
---|---|---|
delay-0 | transition-delay: 0s; | <div className="delay-0"></div> |
delay-75 | transition-delay: 75ms; | <div className="delay-75"></div> |
delay-100 | transition-delay: 100ms; | <div className="delay-100"></div> |
delay-150 | transition-delay: 150ms; | <div className="delay-150"></div> |
delay-200 | transition-delay: 200ms; | <div className="delay-200"></div> |
delay-300 | transition-delay: 300ms; | <div className="delay-300"></div> |
delay-500 | transition-delay: 500ms; | <div className="delay-500"></div> |
delay-700 | transition-delay: 700ms; | <div className="delay-700"></div> |
delay-1000 | transition-delay: 1000ms; | <div className="delay-1000"></div> |
Overview of Transition Delay
Adding the Transition Delay
To add transition delay to an element, use Tailwind's delay utilities- delay-100
, delay-200
, delay-300
, etc.
export default function TransitionDelayDemo() { return ( <div className="h-screen w-screen flex justify-center items-center bg-gray-100"> <button className="px-6 py-3 bg-blue-500 text-white rounded-lg hover:bg-blue-700 transition delay-300"> Hover Me </button> </div> ); }
States and Responsiveness
Hover and Focus States
Tailwind allows you to conditionally apply the transition delay on certain states like hover and focus. Use Tailwind's state modifiers like- hover
, focus
, etc. to apply the utility only when these states are active, e.g., hover:delay-500
.
export default function HoverFocusTransition() { return ( <div className="h-screen w-screen flex justify-center items-center bg-gray-200"> <button className="px-8 py-4 bg-green-500 text-white rounded-lg transition hover:delay-500 focus:bg-green-700 hover:bg-green-600"> Hover Me </button> </div> ); }
Breakpoint Modifiers
Tailwind supports breakpoint modifiers, allowing you to change transition delay based on specific screen breakpoints. This ensures animations adapt for varying viewports, creating a polished appearance across devices.
export default function ResponsiveTransitionDelay() { return ( <div className="h-screen w-screen flex justify-center items-center bg-gray-50"> <div className="w-64 h-64 p-12 text-center bg-yellow-400 transition delay-200 md:delay-500 lg:delay-1000 hover:bg-yellow-500"> Resize the screen to test delays </div> </div> ); }
Custom Transition Delay
In some scenarios, the default transition delay values provided by Tailwind CSS might not cover your specific use cases. Tailwind enables you to extend the theme or apply completely arbitrary values to achieve precise timings.
Extending the Theme
One way to introduce custom delay values is by extending the Tailwind theme configuration in your Tailwind CSS setup. You can define these custom values in your tailwind.config.js
file. The below configuration introduces two custom transition delay values: 1500ms
and 2500ms
.
import tailwindConfig from "./tailwind.config.js"; tailwind.config = tailwindConfig; export default function CustomThemeDelay() { return ( <div className="h-screen w-screen flex justify-center items-center bg-gray-300"> <div className="w-48 h-48 p-12 text-center bg-red-400 transition delay-1500 hover:bg-red-500"> 1.5s Delay </div> </div> ); }
Using Arbitrary Values
For one-off customizations, Tailwind CSS supports arbitrary values. These values can be applied inline with the utility class syntax, wrapped in square brackets.
export default function ArbitraryDelayValue() { return ( <div className="h-screen w-screen flex justify-center items-center gap-4 bg-white"> <div className="w-36 h-36 bg-indigo-500 transition delay-[750ms] hover:bg-indigo-600 p-2 text-center"> 750ms Delay </div> <div className="w-36 h-36 bg-purple-500 transition delay-[1500ms] hover:bg-purple-600 p-2 text-center"> 1.5s Delay </div> </div> ); }
Real World Examples
Info Cards
A grid of product cards that reveal additional details on hover with staggered delays.
const HoverInfoCards = () => { const products = [ { id: 1, name: "Premium Headphones", price: "$299", src: "https://images.unsplash.com/photo-1505740420928-5e560c06d30e", specs: ["40mm Drivers", "20Hz-20kHz", "Wireless", "32 Ohm", "USB-C", "ANC"] }, { id: 2, name: "Mechanical Keyboard", price: "$159", src: "https://images.unsplash.com/photo-1511467687858-23d96c32e4ae", specs: ["Cherry MX", "RGB", "TKL", "Hot-swap", "USB-C", "PBT Caps"] }, { id: 3, name: "Wireless Mouse", price: "$79", src: "https://images.unsplash.com/photo-1527864550417-7fd91fc51a46", specs: ["20K DPI", "Wireless", "RGB", "6 Buttons", "USB-C", "Gaming"] }, { id: 4, name: "4K Monitor", price: "$499", src: "https://images.unsplash.com/photo-1527443224154-c4a3942d3acf", specs: ["27-inch", "4K UHD", "144Hz", "1ms", "HDR", "HDMI 2.1"] }, { id: 5, name: "Gaming Chair", price: "$249", src: "https://images.unsplash.com/photo-1598550473359-433795503a0f", specs: ["Ergonomic", "Recline", "4D Arms", "Lumbar", "PU Leather", "RGB"] }, { id: 6, name: "Webcam Pro", price: "$129", src: "https://images.unsplash.com/photo-1629429408209-1f912961dbd8", specs: ["4K", "60FPS", "HDR", "AF", "Privacy", "USB-C"] } ]; return ( <div className="grid grid-cols-2 gap-3 p-4 bg-gray-100"> {products.map((product) => ( <div key={product.id} className="relative bg-white rounded-lg overflow-hidden shadow-sm group" > <img src={product.src} alt={product.name} className="w-full h-32 object-cover" /> <div className="p-3"> <h3 className="text-sm font-semibold">{product.name}</h3> <p className="text-xs text-gray-600">{product.price}</p> {/* Specs that appear on hover */} <div className="absolute inset-0 bg-black/80 text-white opacity-0 group-hover:opacity-100 transition-opacity duration-300"> <div className="p-3"> <h4 className="text-sm font-semibold mb-2">Specifications</h4> <div className="grid grid-cols-2 gap-2"> {product.specs.map((spec, index) => ( <span key={spec} className={`text-xs opacity-0 transform translate-y-2 group-hover:opacity-100 group-hover:translate-y-0 transition-all duration-300 delay-${index * 100}`} > {spec} </span> ))} </div> </div> </div> </div> </div> ))} </div> ); }; export default HoverInfoCards;
Social Links Menu
A menu where social links expand with sequential delays on hover.
const SocialLinks = () => { const socialLinks = [ { id: 1, name: "Twitter", icon: "https://images.unsplash.com/photo-1611162618479-ee3d24aaef0b", username: "@techcompany", followers: "125K" }, { id: 2, name: "Instagram", icon: "https://images.unsplash.com/photo-1611162616305-c69b3fa7fbe0", username: "@techcompany", followers: "89K" }, { id: 3, name: "LinkedIn", icon: "https://images.unsplash.com/photo-1611944212129-29977ae1398c", username: "Tech Company", followers: "45K" }, { id: 4, name: "GitHub", icon: "https://images.unsplash.com/photo-1618401471353-b98afee0b2eb", username: "techcompany", followers: "2.3K" }, { id: 5, name: "YouTube", icon: "https://images.unsplash.com/photo-1611162616475-46b635cb6868", username: "TechCompany", followers: "200K" }, { id: 6, name: "Discord", icon: "https://images.unsplash.com/photo-1614680376739-414d95ff43df", username: "tech.community", followers: "15K" } ]; return ( <div className="p-4 space-y-2"> {socialLinks.map((social) => ( <div key={social.id} className="group flex items-center bg-white rounded-lg p-2 cursor-pointer hover:bg-gray-50 transition-colors duration-300" > <img src={social.icon} alt={social.name} className="w-8 h-8 rounded-full" /> <div className="ml-3 overflow-hidden"> <p className="text-sm font-medium">{social.name}</p> <div className="flex space-x-4"> <span className="text-xs text-gray-500 opacity-0 transform -translate-x-4 group-hover:opacity-100 group-hover:translate-x-0 transition-all duration-300 delay-100" > {social.username} </span> <span className="text-xs text-blue-500 opacity-0 transform -translate-x-4 group-hover:opacity-100 group-hover:translate-x-0 transition-all duration-300 delay-200" > {social.followers} </span> </div> </div> </div> ))} </div> ); }; export default SocialLinks;
Feature Grid Expansion
A grid of feature cards that expand to show more details on hover with delayed transitions.
const FeatureGrid = () => { const features = [ { id: 1, title: "Cloud Storage", icon: "https://images.unsplash.com/photo-1611162616305-c69b3fa7fbe0", description: "Secure cloud storage with encryption", details: ["End-to-end encryption", "Automatic backup", "File versioning", "Sharing controls", "Access logs", "2FA"] }, { id: 2, title: "Analytics", icon: "https://images.unsplash.com/photo-1551288049-bebda4e38f71", description: "Real-time data insights", details: ["Custom reports", "Data export", "API access", "Live dashboard", "Alerts", "Integrations"] }, { id: 3, title: "Collaboration", icon: "https://images.unsplash.com/photo-1633332755192-727a05c4013d", description: "Team workspace and tools", details: ["Chat rooms", "File sharing", "Task boards", "Calendar", "Notes", "Video calls"] }, { id: 4, title: "Security", icon: "https://images.unsplash.com/photo-1496368077930-c1e31b4e5b44", description: "Enterprise-grade protection", details: ["Firewall", "VPN", "Monitoring", "Backups", "Compliance", "Audit logs"] }, { id: 5, title: "Integration", icon: "https://images.unsplash.com/photo-1551288049-bebda4e38f71", description: "Connect your tools", details: ["REST API", "Webhooks", "SSO", "Custom apps", "SDK", "Support"] }, { id: 6, title: "Support", icon: "https://images.unsplash.com/photo-1611162616305-c69b3fa7fbe0", description: "24/7 expert assistance", details: ["Live chat", "Phone", "Email", "FAQ", "Docs", "Training"] } ]; return ( <div className="grid grid-cols-2 grid-rows-4 gap-3 p-4"> {features.map((feature) => ( <div key={feature.id} className="group bg-white p-3 rounded-lg shadow-sm hover:shadow-md hover:row-span-2 transition-all duration-300 overflow-hidden relative" > <div className="flex items-center mb-2"> <img src={feature.icon} alt="" className="w-8 h-8 rounded-full" /> <h3 className="text-sm font-semibold ml-2">{feature.title}</h3> </div> <p className="text-xs text-gray-600">{feature.description}</p> {/* Expandable details */} <div className="absolute inset-0 bg-blue-50 p-3 translate-y-full group-hover:translate-y-0 transition-transform duration-300"> <h4 className="text-sm font-semibold mb-2">{feature.title}</h4> <div className="grid grid-cols-2 gap-2"> {feature.details.map((detail, index) => ( <span key={detail} className={`text-xs text-gray-600 opacity-0 transform translate-y-2 group-hover:opacity-100 group-hover:translate-y-0 transition-all duration-300 delay-${index * 50}`} > • {detail} </span> ))} </div> </div> </div> ))} </div> ); }; export default FeatureGrid;
Pricing Card Comparison
A set of pricing cards that reveal feature comparisons on hover with delayed animations.
const PricingCards = () => { const plans = [ { id: 1, name: "Basic", price: "$9", period: "/month", features: [ "2 GB Storage", "10 Projects", "Basic Support", "1 User", "API Access", "Weekly Backups" ] }, { id: 2, name: "Pro", price: "$19", period: "/month", features: [ "10 GB Storage", "50 Projects", "Priority Support", "5 Users", "API Access", "Daily Backups" ] }, { id: 3, name: "Team", price: "$49", period: "/month", features: [ "100 GB Storage", "Unlimited Projects", "24/7 Support", "20 Users", "API Access", "Real-time Backups" ] } ]; return ( <div className="p-4 space-y-3"> {plans.map((plan) => ( <div key={plan.id} className="group relative bg-white rounded-lg p-4 hover:h-64 shadow-sm hover:shadow-md transition-shadow duration-300" > <div className="flex justify-between items-baseline"> <h3 className="text-lg font-semibold">{plan.name}</h3> <div className="text-right"> <span className="text-2xl font-bold">{plan.price}</span> <span className="text-sm text-gray-500">{plan.period}</span> </div> </div> {/* Feature comparison overlay */} <div className="absolute inset-0 bg-white/95 opacity-0 group-hover:opacity-100 transition-opacity duration-300"> <div className="p-4"> <h4 className="text-sm font-semibold mb-3">Plan Features</h4> {plan.features.map((feature, index) => ( <div key={feature} className={`flex items-center text-sm mb-2 opacity-0 transform translate-x-2 group-hover:opacity-100 group-hover:translate-x-0 transition-all duration-300 delay-${index * 100}`} > <svg className="w-4 h-4 text-green-500 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" /> </svg> {feature} </div> ))} </div> </div> </div> ))} </div> ); }; export default PricingCards;
Profile Cards Expansion
A grid of team member profile cards that expand to show additional info with delayed animations.
const ProfileCards = () => { const profiles = [ { id: 1, name: "Alex Chen", role: "Product Designer", src: "https://images.unsplash.com/photo-1472099645785-5658abf4ff4e", skills: ["UI/UX", "Figma", "Prototyping", "Research", "Animation", "Design Systems"], details: { experience: "5+ years", projects: "45+", location: "San Francisco" } }, { id: 2, name: "Sarah Miller", role: "Frontend Developer", src: "https://images.unsplash.com/photo-1494790108377-be9c29b29330", skills: ["React", "Tailwind", "TypeScript", "Next.js", "Testing", "Performance"], details: { experience: "4+ years", projects: "38+", location: "New York" } }, { id: 3, name: "James Wilson", role: "Backend Developer", src: "https://images.unsplash.com/photo-1500648767791-00dcc994a43e", skills: ["Node.js", "Python", "AWS", "Docker", "GraphQL", "MongoDB"], details: { experience: "6+ years", projects: "52+", location: "London" } }, { id: 4, name: "Emily Davis", role: "Project Manager", src: "https://images.unsplash.com/photo-1438761681033-6461ffad8d80", skills: ["Agile", "Scrum", "Jira", "Leadership", "Strategy", "Communication"], details: { experience: "7+ years", projects: "60+", location: "Berlin" } }, { id: 5, name: "Michael Park", role: "DevOps Engineer", src: "https://images.unsplash.com/photo-1472099645785-5658abf4ff4e", skills: ["Kubernetes", "Jenkins", "AWS", "Terraform", "CI/CD", "Monitoring"], details: { experience: "5+ years", projects: "42+", location: "Toronto" } }, { id: 6, name: "Lisa Chang", role: "UX Researcher", src: "https://images.unsplash.com/photo-1494790108377-be9c29b29330", skills: ["User Testing", "Analytics", "Interviews", "Wireframing", "A/B Testing", "Personas"], details: { experience: "4+ years", projects: "35+", location: "Singapore" } } ]; return ( <div className="grid grid-cols-2 gap-3 p-4"> {profiles.map((profile) => ( <div key={profile.id} className="group relative bg-white rounded-lg shadow-sm overflow-hidden hover:shadow-md transition-shadow duration-300" > <div className="p-3"> <img src={profile.src} alt={profile.name} className="w-16 h-16 rounded-full mx-auto mb-2" /> <h3 className="text-sm font-semibold text-center">{profile.name}</h3> <p className="text-xs text-gray-600 text-center">{profile.role}</p> </div> {/* Expandable content */} <div className="absolute inset-0 bg-gradient-to-b from-blue-500 to-blue-600 text-white opacity-0 group-hover:opacity-100 transition-opacity duration-300"> <div className="p-4"> <div className="mb-3"> <h4 className="text-sm font-semibold mb-2">Details</h4> {Object.entries(profile.details).map(([key, value], index) => ( <div key={key} className={`text-xs opacity-0 transform -translate-y-2 group-hover:opacity-100 group-hover:translate-y-0 transition-all duration-300 delay-${index * 100}`} > <span className="font-medium">{key}: </span> {value} </div> ))} </div> <div> <h4 className="text-sm font-semibold mb-2">Skills</h4> <div className="grid grid-cols-2 gap-1"> {profile.skills.map((skill, index) => ( <span key={skill} className={`text-xs bg-white/20 rounded px-2 py-1 opacity-0 transform translate-y-2 group-hover:opacity-100 group-hover:translate-y-0 transition-all duration-300 delay-${index * 100 + 300}`} > {skill} </span> ))} </div> </div> </div> </div> </div> ))} </div> ); }; export default ProfileCards;
Customization Examples
Expandable Info Card
A card that reveals additional information with a staggered delay on hover.
import tailwindConfig from "./tailwind.config.js"; tailwind.config = tailwindConfig; const ExpandableCard = () => { return ( <div className="w-screen h-[400px] p-4 bg-gray-100"> <div className="relative overflow-hidden rounded-xl bg-white shadow-sm hover:shadow-lg transition-all duration-300 p-4 group"> <img src="https://images.unsplash.com/photo-1618005182384-a83a8bd57fbe" alt="Product" className="w-full h-48 object-cover rounded-lg" /> <h3 className="mt-3 text-lg font-semibold">Wireless Headphones</h3> <p className="text-sm text-gray-500">Premium Sound Quality</p> {/* Hidden content that appears on hover */} <div className="absolute inset-0 bg-black/80 opacity-0 group-hover:opacity-100 transition-opacity duration-300 flex flex-col justify-end p-4"> <h4 className="text-white font-medium transform translate-y-4 opacity-0 group-hover:translate-y-0 group-hover:opacity-100 transition-all duration-300 delay-info-1"> Technical Specs </h4> <p className="text-gray-300 text-sm transform translate-y-4 opacity-0 group-hover:translate-y-0 group-hover:opacity-100 transition-all duration-300 delay-info-2"> 40mm Drivers • 20Hz-20kHz Active Noise Cancelling </p> <button className="mt-3 bg-white text-black px-4 py-2 rounded-lg text-sm transform translate-y-4 opacity-0 group-hover:translate-y-0 group-hover:opacity-100 transition-all duration-300 delay-info-3"> Learn More </button> </div> </div> </div> ); }; export default ExpandableCard;
Feature Showcase
A component that reveals feature details with cascading delays on hover.
import tailwindConfig from "./tailwind.config.js"; tailwind.config = tailwindConfig; const FeatureShowcase = () => { return ( <div className="w-screen h-[400px] bg-gray-100 p-4"> <div className="bg-white rounded-xl p-4 group"> <div className="space-y-4"> {[ { title: "Cloud Storage", desc: "Store files securely in the cloud" }, { title: "Sync", desc: "Real-time synchronization across devices" }, { title: "Share", desc: "Easy file sharing with team members" } ].map((feature, index) => ( <div key={index} className="relative overflow-hidden rounded-lg bg-gray-50 p-3 hover:bg-blue-50 transition-colors duration-300" > <h3 className="font-medium text-gray-800">{feature.title}</h3> <div className={`overflow-hidden h-0 group-hover:h-12 transition-all duration-300 delay-feature-${index + 1}`}> <p className="text-sm text-gray-600 mt-2">{feature.desc}</p> </div> </div> ))} </div> </div> </div> ); }; export default FeatureShowcase;
Layered Image Reveal
An image component that reveals multiple layers with different delays on hover.
// LayeredImage.js import React from 'react'; const LayeredImage = () => { return ( <div className="w-screen h-[400px] bg-gray-100 p-4"> <div className="relative group overflow-hidden rounded-xl"> <img src="https://images.unsplash.com/photo-1501785888041-af3ef285b470" alt="Landscape" className="w-full h-[300px] object-cover" /> {/* Overlay layers */} <div className="absolute inset-0 bg-gradient-to-t from-black/70 to-transparent transform translate-y-full group-hover:translate-y-0 transition-transform duration-500 delay-layer-1" /> <div className="absolute bottom-0 left-0 right-0 p-4 transform translate-y-full group-hover:translate-y-0 transition-transform duration-500 delay-layer-2"> <h3 className="text-white text-lg font-semibold">Mountain Lake</h3> <p className="text-gray-200 text-sm">Captured at sunrise</p> </div> <button className="absolute bottom-4 right-4 bg-white text-black px-4 py-2 rounded-lg text-sm transform translate-y-20 opacity-0 group-hover:translate-y-0 group-hover:opacity-100 transition-all duration-500 delay-layer-3"> View Gallery </button> </div> </div> ); }; export default LayeredImage;
Best Practices
Maintain Design Consistency
Transition effects should align with the overall theme and pacing of animations across your project. For example, if one button uses a delay-300
utility for hover effects, ensure that similar buttons across the UI adopt the same delay timing.
If custom delay utilities are needed apart from the predetermined ones- define them within your tailwind.config.js
to maintain consistency. These custom delay values can then become the default palette for your animations. This approach makes your transitions predictable and avoids excessive variation that might confuse users.
Leverage Utility Combinations
Combining transition-delay
with other Tailwind utilities can help you achieve advanced animations while maintaining a utility-first approach. For example, layering transform
classes like hover:scale-105
with delay-500
and duration-500
creates hover effects that feel both dynamic and seamless.
For complex animations, such as cascading modals or progressive reveals, experiment with state variants like hover
, focus
, etc. in combination with transition
, delay
, and layout utilities. An example is pairing opacity-0
with hover:opacity-100
for fade-in effects.
Accessibility Considerations
Enhance Readability and Navigability
When applying transition-delay
in a Tailwind CSS project, always consider how animations affect the readability and navigability of content. Delays should guide attention, not hinder it. For example, using delay-200
to smoothly transition text-based elements allows readers to focus sequentially without creating visual clutter.
Animations should support content flow rather than distract users. Use utilities like opacity-0
, paired with delay-300
and hover:opacity-100
, to create fade-ins specifically for less critical content. Keep transitions short to avoid obstructing access to essential features, particularly for assistive technology users who rely on screen readers and other tools.
Focus on High Contrast
High-contrast interfaces benefit significantly from properly configured transition-delay
utilities. Adding delays like delay-200
for hover states help users perceive color transitions more clearly. For example, transitioning from bg-gray-700
to bg-yellow-400
ensures high contrast differences remain visually distinct.
Ensure that combining transition-delay
with other utilities like focus:ring
and outline-none
highlights interacted or focused elements without compromising readability. Set delays conservatively to avoid overshadowing the contrast or animations taking too long to visually establish new states.