Tailwind CSS Box Shadow
Box shadows are a fundamental styling property in CSS, allowing you to add depth and visual appeal to your elements by creating an illusion of elevation. In traditional CSS, the box-shadow
property defines one or more shadows to an element's box. With Tailwind CSS, you get a predefined set of utilities to handle box shadows effortlessly, ranging from subtle shadows to deep, dramatic effects. Tailwind provides intuitive class names to customize shadows quickly, while still offering full flexibility for specific customizations.
In this article, you’ll learn how to use Tailwind’s box shadow utilities effectively, how to conditionally apply shadows with states and responsive modifiers, and how to extend your theme or use arbitrary values to implement custom shadows.
Class | Properties | Example |
---|---|---|
shadow-sm | box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); | <div className="shadow-sm"></div> |
shadow | box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); | <div className="shadow"></div> |
shadow-md | box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); | <div className="shadow-md"></div> |
shadow-lg | box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); | <div className="shadow-lg"></div> |
shadow-xl | box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1); | <div className="shadow-xl"></div> |
shadow-2xl | box-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25); | <div className="shadow-2xl"></div> |
shadow-inner | box-shadow: inset 0 2px 4px 0 rgb(0 0 0 / 0.05); | <div className="shadow-inner"></div> |
shadow-none | box-shadow: 0 0 #0000; | <div className="shadow-none"></div> |
Overview of Box Shadow
The box shadow utilities in Tailwind CSS make it easy to add, modify, and even remove shadows on elements. Let’s explore some common ways you can use these utilities.
Adding the Box Shadow
A basic outer shadow can be added by using Tailwind's predefined shadow utilities. These shadows give your elements an aesthetic lift and can range from small, subtle effects to large, prominent ones.
export default function Card() { return ( <div className="flex items-center justify-center h-screen w-screen bg-gray-50"> <div className="shadow-lg p-6 rounded-md bg-white"> <img className="rounded-t-md" src="https://images.unsplash.com/photo-1508873699372-7aeab60b44ab" alt="Sample" /> <h2 className="mt-4 text-xl font-semibold">Title with Shadow</h2> <p className="mt-2 text-gray-600"> This element has an **outer shadow** using Tailwind's shadow utilities. </p> </div> </div> ); }
Above configuration corresponds to:
shadow-lg
: Applies a large shadow with respectively larger offsets and blurs.
Creating an Inner Shadow Effect
Inner shadows can make elements appear recessed or carved-in. In Tailwind CSS, this effect is achieved using the shadow-inner
utility.
export default function InnerShadowCard() { return ( <div className="flex items-center justify-center h-screen w-screen bg-gray-50"> <div className="shadow-inner shadow-red-200 bg-gray-200 h-60 w-60 flex items-center justify-center rounded-lg"> <p className="text-gray-800 font-medium"> Inner Shadow Applied </p> </div> </div> ); }
How this works:
shadow-inner
: Places the shadow inside the element, creating a recessed effect.
Disabling Shadows Entirely
If you need an element without any shadow, Tailwind offers shadow-none
to remove all shadow styles.
export default function PlainCard() { return ( <div className="flex items-center justify-center h-screen w-screen bg-gray-50"> <div className="shadow-none bg-gray-100 h-40 w-40 p-4 rounded-lg"> <p className="text-gray-600 text-center"> No Shadow Here </p> </div> </div> ); }
States and Responsiveness
Tailwind allows you to conditionally apply box shadows based on interactive states like hover and focus, as well as responsive breakpoints for dynamic designs.
Hover and Focus States
Using state modifiers such as hover:
or focus:
, you can create interactive effects when a user interacts with your elements.
export default function HoverShadowCard() { return ( <div className="flex items-center justify-center h-screen w-screen bg-gray-50"> <div className="bg-white p-6 rounded-lg shadow-md hover:shadow-2xl transition-shadow duration-300"> <h2 className="text-gray-800 font-bold">Hover Over Me</h2> <p className="text-gray-500 mt-2"> The shadow becomes **bigger** when hovered! </p> </div> </div> ); }
State configuration:
hover:shadow-2xl
: Intensifies the shadow upon hovering.
Breakpoint Modifiers
Tailwind also enables conditional shadowing via breakpoint-specific modifiers, letting you define shadows for different screen sizes.
export default function ResponsiveShadowCard() { return ( <div className="flex items-center justify-center h-screen w-screen bg-gray-50"> <div className="bg-white p-6 rounded-lg shadow-sm md:shadow lg:shadow-2xl"> <h2 className="text-gray-900 font-bold">Responsive Shadows</h2> <p className="text-gray-600 mt-2"> Shadows vary based on screen size! </p> </div> </div> ); }
Breakpoint behaviour:
shadow-sm
: Default shadow for small screens.md:shadow
,lg:shadow-2xl
: Gradually increases shadow strength on medium and large screens.
Custom Box Shadow
Aside from its predefined utilities, Tailwind CSS provides tools for customization when default shadows don’t meet your specific design requirements. You can accomplish this by extending your theme or using arbitrary values.
Extending the Theme
You can define custom shadow values in your tailwind.config.js
to create reusable shadow classes tailored to your preferences. This customization keeps your code DRY while meeting your unique design needs.
Then use it as follows:
import tailwindConfig from "./tailwind.config.js"; tailwind.config = tailwindConfig; export default function CustomShadowCard() { return ( <div className="flex items-center justify-center h-screen w-screen bg-gray-50"> <div className="shadow-custom-dark bg-gray-800 h-40 w-40 rounded-lg flex justify-center items-center"> <p className="text-white text-center font-medium"> Custom Shadow </p> </div> </div> ); }
By defining shadow-custom-dark
in your theme, you standardize a reusable custom shadow.
Using Arbitrary Values
For quick, one-off shadow requirements, Tailwind supports arbitrary values directly in your HTML or JSX using square brackets.
export default function ArbitraryShadowCard() { return ( <div className="flex items-center justify-center h-screen w-screen bg-gray-50"> <div className="bg-white h-40 w-40 shadow-[10px_10px_15px_rgba(0,0,0,0.4)] rounded-lg flex items-center justify-center px-4 text-center"> <p> Arbitrary Value Shadow </p> </div> </div> ); }
How the arbitrary utility works:
shadow-[10px_10px_15px_rgba(0,0,0,0.4)]
: Directly applies a shadow offset, blur, and color in one line.
Real World Examples
Product Cards with Hover Effect
This example shows a grid of product cards with a subtle shadow that intensifies on hover, creating a floating effect.
export default function ProductGrid() { const products = [ { id: 1, name: "Leather Backpack", price: "$129.99", src: "https://images.unsplash.com/photo-1548036328-c9fa89d128fa", alt: "Brown leather backpack" }, { id: 2, name: "Wireless Headphones", price: "$199.99", src: "https://images.unsplash.com/photo-1505740420928-5e560c06d30e", alt: "Black wireless headphones" }, { id: 3, name: "Smart Watch", price: "$299.99", src: "https://images.unsplash.com/photo-1523275335684-37898b6baf30", alt: "Modern smartwatch" }, { id: 4, name: "Digital Camera", price: "$799.99", src: "https://images.unsplash.com/photo-1516035069371-29a1b244cc32", alt: "Professional digital camera" }, { id: 5, name: "Laptop Stand", price: "$49.99", src: "https://images.unsplash.com/photo-1527864550417-7fd91fc51a46", alt: "Aluminum laptop stand" }, { id: 6, name: "Mechanical Keyboard", price: "$159.99", src: "https://images.unsplash.com/photo-1511467687858-23d96c32e4ae", alt: "RGB mechanical keyboard" } ]; return ( <div className="grid grid-cols-1 md:grid-cols-3 gap-6 p-6"> {products.map((product) => ( <div key={product.id} className="bg-white rounded-lg shadow-md hover:shadow-xl transition-shadow duration-300 ease-in-out" > <img src={product.src} alt={product.alt} className="w-full h-48 object-cover rounded-t-lg" /> <div className="p-4"> <h3 className="text-lg font-semibold">{product.name}</h3> <p className="text-gray-600">{product.price}</p> </div> </div> ))} </div> ); }
Floating Action Menu
This example demonstrates a floating action button that expands into a menu with multiple options.
export default function FloatingActionMenu() { const menuItems = [ { id: 1, label: "Add Post", icon: "https://images.unsplash.com/photo-1618477247222-acbdb0e159b3", alt: "Add post icon" }, { id: 2, label: "Upload Photo", icon: "https://images.unsplash.com/photo-1618477247222-acbdb0e159b3", alt: "Upload photo icon" }, { id: 3, label: "Share Location", icon: "https://images.unsplash.com/photo-1618477247222-acbdb0e159b3", alt: "Location icon" }, { id: 4, label: "Start Live", icon: "https://images.unsplash.com/photo-1618477247222-acbdb0e159b3", alt: "Live streaming icon" }, { id: 5, label: "Create Poll", icon: "https://images.unsplash.com/photo-1618477247222-acbdb0e159b3", alt: "Poll icon" }, { id: 6, label: "Settings", icon: "https://images.unsplash.com/photo-1618477247222-acbdb0e159b3", alt: "Settings icon" } ]; return ( <div className="fixed bottom-6 right-6"> <div className="group"> <button className="w-14 h-14 bg-blue-500 rounded-full shadow-lg hover:shadow-xl transition-shadow duration-300"> <span className="text-white text-2xl">+</span> </button> <div className="absolute bottom-16 right-0 hidden group-hover:block"> {menuItems.map((item) => ( <button key={item.id} className="block w-48 mb-2 p-3 bg-white rounded-lg shadow-lg hover:shadow-xl transition-shadow duration-300" > <span>{item.label}</span> </button> ))} </div> </div> </div> ); }
Stacked Notification Cards
This example shows a stack of notification cards with layered shadows creating depth.
export default function NotificationStack() { const notifications = [ { id: 1, title: "New Message", message: "John Doe sent you a message", time: "2 minutes ago", type: "message" }, { id: 2, title: "Payment Received", message: "Payment of $500 received", time: "15 minutes ago", type: "payment" }, { id: 3, title: "New Order", message: "Order #12345 has been placed", time: "1 hour ago", type: "order" }, { id: 4, title: "System Update", message: "System maintenance scheduled", time: "2 hours ago", type: "system" }, { id: 5, title: "New Follow", message: "Jane Smith started following you", time: "3 hours ago", type: "social" }, { id: 6, title: "Storage Alert", message: "Storage space running low", time: "4 hours ago", type: "alert" } ]; return ( <div className="p-6"> {notifications.map((notification, index) => ( <div key={notification.id} className={`bg-white rounded-lg p-4 mb-3 transform transition-all duration-300 hover:-translate-y-1 ${ index === 0 ? 'shadow-2xl' : index === 1 ? 'shadow-xl' : 'shadow-md' }`} > <h4 className="font-semibold">{notification.title}</h4> <p className="text-gray-600">{notification.message}</p> <span className="text-sm text-gray-400">{notification.time}</span> </div> ))} </div> ); }
Pricing Table with Emphasized Tier
This example displays a pricing table where the recommended tier has a pronounced shadow.
export default function PricingTable() { const plans = [ { id: 1, name: "Basic", price: "$9.99", features: ["1 User", "5GB Storage", "Basic Support", "Email Access", "Community Forums", "Basic Analytics"], recommended: false }, { id: 2, name: "Pro", price: "$29.99", features: ["5 Users", "50GB Storage", "Priority Support", "Email & Phone Access", "Advanced Analytics", "API Access"], recommended: true }, { id: 3, name: "Enterprise", price: "$99.99", features: ["Unlimited Users", "500GB Storage", "24/7 Support", "Dedicated Manager", "Custom Analytics", "White Labeling"], recommended: false } ]; return ( <div className="flex flex-col md:flex-row gap-6 p-6"> {plans.map((plan) => ( <div key={plan.id} className={`flex-1 bg-white rounded-lg p-6 ${ plan.recommended ? 'shadow-2xl transform -translate-y-4' : 'shadow-md hover:shadow-lg transition-shadow duration-300' }`} > <h3 className="text-xl font-bold">{plan.name}</h3> <p className="text-3xl font-bold my-4">{plan.price}</p> <ul className="space-y-2"> {plan.features.map((feature, index) => ( <li key={index} className="flex items-center"> <span className="mr-2">✓</span> {feature} </li> ))} </ul> </div> ))} </div> ); }
Modal Dialog with Backdrop Shadow
This example shows a modal dialog with a backdrop shadow and elevated content.
export default function ModalDialog() { const modalContent = { title: "Confirm Action", message: "Are you sure you want to proceed with this action?", options: [ { id: 1, label: "Cancel", type: "secondary" }, { id: 2, label: "Confirm", type: "primary" } ], additionalInfo: [ "This action cannot be undone", "All related data will be affected", "System notifications will be sent", "Audit logs will be updated", "Backup will be created automatically", "Process may take a few minutes" ] }; return ( <div className="fixed inset-0 flex items-center justify-center"> <div className="fixed inset-0 bg-black bg-opacity-50"></div> <div className="relative bg-white rounded-lg shadow-2xl w-full max-w-md m-4 p-6"> <h2 className="text-xl font-bold mb-4">{modalContent.title}</h2> <p className="text-gray-600 mb-4">{modalContent.message}</p> <ul className="mb-6"> {modalContent.additionalInfo.map((info, index) => ( <li key={index} className="text-sm text-gray-500 mb-1"> • {info} </li> ))} </ul> <div className="flex justify-end space-x-4"> {modalContent.options.map((option) => ( <button key={option.id} className={`px-4 py-2 rounded ${ option.type === 'primary' ? 'bg-blue-500 text-white shadow-md hover:shadow-lg' : 'bg-gray-200 text-gray-800' } transition-shadow duration-300`} > {option.label} </button> ))} </div> </div> </div> ); }
Customization Examples
Here are three distinct examples of customizing box shadows in Tailwind CSS through theme configuration. Each example demonstrates different approaches to implementing custom shadows for specific UI components.
Gradient-Enhanced Product Card Shadow
This example shows how to create a product card with a sophisticated shadow that includes subtle gradient effects.
import tailwindConfig from "./tailwind.config.js"; tailwind.config = tailwindConfig; export default function ProductCard() { return ( <div className="flex justify-center items-center min-h-screen bg-gray-100"> <div className="w-80 bg-white rounded-xl shadow-product transform hover:scale-105 transition-all duration-300"> <img src="https://images.unsplash.com/photo-1523275335684-37898b6baf30" alt="Premium Watch" className="w-full h-48 object-cover rounded-t-xl" /> <div className="p-6"> <h2 className="text-2xl font-bold text-gray-800">Premium Watch</h2> <p className="mt-2 text-gray-600">Limited Edition Timepiece</p> <div className="mt-4 flex justify-between items-center"> <span className="text-xl font-bold text-blue-600">$299.99</span> <button className="px-4 py-2 bg-blue-500 text-white rounded-lg"> Add to Cart </button> </div> </div> </div> </div> ) }
Floating Navigation Menu Shadow
This example demonstrates a floating navigation menu with a sophisticated multi-layered shadow effect.
import tailwindConfig from "./tailwind.config.js"; tailwind.config = tailwindConfig; export default function FloatingNavigation() { return ( <nav className="fixed bottom-8 left-1/2 transform -translate-x-1/2 bg-white shadow-float-nav rounded-full px-8 py-4"> <ul className="flex space-x-12"> {['Home', 'Search', 'Profile', 'Settings'].map((item) => ( <li key={item} className="flex flex-col items-center"> <img src={`https://images.unsplash.com/photo-1512941937669-90a1b58e7e9c?w=20`} alt={item} className="w-6 h-6 mb-1" /> <span className="text-sm text-gray-600">{item}</span> </li> ))} </ul> </nav> ) }
Notification Toast Shadow
This example showcases a notification toast with a directional shadow effect.
import tailwindConfig from "./tailwind.config.js"; tailwind.config = tailwindConfig; export default function NotificationToast() { return ( <div className="fixed top-8 right-8 max-w-md"> <div className="bg-white shadow-toast rounded-lg p-6 transform transition-transform hover:-translate-y-1"> <div className="flex items-start"> <div className="flex-shrink-0"> <img src="https://images.unsplash.com/photo-1560250097-0b93528c311a?w=50" alt="Profile" className="w-10 h-10 rounded-full" /> </div> <div className="ml-4"> <h3 className="text-lg font-semibold text-gray-900">New Message</h3> <p className="mt-1 text-gray-600"> You have received a new message from John Doe. </p> <div className="mt-4 flex space-x-3"> <button className="px-4 py-2 bg-blue-500 text-white rounded-md"> View </button> <button className="px-4 py-2 bg-gray-200 text-gray-700 rounded-md"> Dismiss </button> </div> </div> </div> </div> </div> ) }
These examples demonstrate how you can create custom box shadows for different UI components using Tailwind CSS's theme customization. Each shadow is carefully crafted to enhance the visual hierarchy and interaction states of the components while maintaining a consistent design language.
Best Practices
Maintain Design Consistency
When implementing Box Shadow in your project with Tailwind CSS, ensure all shadow effects align with your design system. Consistency facilitates a cohesive user experience and reinforces your brand identity. Opt for utilizing pre-configured shadow classes like shadow-md
or shadow-lg
across similar elements, such as cards, buttons, and modals. This avoids a mismatched visual hierarchy and simplifies team collaboration.
If unique shadows are needed, extend them through tailwind.config.js
. For instance, define shadows specific to your theme or brand aesthetic:
Use these utilities sparingly throughout your project so that design remains harmonious. Avoid combining stylistically conflicting shadow effects that can confuse or distract your audience.
Leverage Utility Combinations
Design complex visual effects by mixing Tailwind's other utilities with Box Shadow. Combine utility classes such as rounded-xl
, bg-gradient-to-r
, or border
alongside shadows to create polished, professional designs. For example, a notification card may pair a shadow with a side border:
import tailwindConfig from "./tailwind.config.js"; tailwind.config = tailwindConfig; export default function NotificationCard() { return ( <div className="max-w-md mx-auto p-4 bg-white rounded-lg shadow-brand-subtle border-l-4 border-blue-500"> <h3 className="text-lg font-semibold">Update Available</h3> <p className="mt-2 text-gray-600"> Your system has a new software update. Keep everything up-to-date for optimal performance. </p> </div> ); }
Thoughtful utility combinations allow you to achieve intricate styles without custom CSS, ensuring maintainable and scalable code. Keep semantic classes like hover:
, sm:
, or focus:
as part of your combinations to enhance both interactivity and responsiveness.
Accessibility Considerations
Enhance Readability and Navigability
Using Box Shadow strategically can improve readability and navigability for all users, including individuals with visual impairments. Shadows create separation between elements, reducing cognitive load when scanning content. For example, in a card-based layout, distributing subtle shadows (shadow-sm
) around cards helps users distinguish interactive regions.
Contrast can also be enhanced with shadows to prioritize accessibility on low-contrast backgrounds. For instance, pairing a larger shadow (shadow-lg
) with light background colors boosts clarity.
export default function AccessibleCard() { return ( <div className="max-w-sm p-4 mx-auto bg-white rounded-xl shadow-lg"> <img className="h-48 w-full object-cover rounded-lg" src="https://images.unsplash.com/photo-1517059224940-d4af9eec41b7" alt="Accessible Content" /> <h3 className="mt-3 text-gray-900 font-bold">Enhanced Readability</h3> <p className="text-gray-700"> Consistent use of shadows reduces visual clutter while enhancing key content. </p> </div> ); }
By choosing softer shadows, you guide user attention without overwhelming the interface.
Focus on High Contrast
Proper implementation of shadows can improve contrast ratios, ensuring sufficient differentiation between interactive and non-interactive elements. Particularly for buttons or input elements, shadows such as shadow-md
clarify hover states or on-click feedback.
For visually impaired users, hover effects in conjunction with shadows create dynamic depth and make the active component noticeable:
export default function ContrastButton() { return ( <div className="flex justify-center items-center h-screen w-screen"> <button className="bg-blue-500 hover:shadow-xl shadow-md text-white font-semibold py-2 px-6 rounded-lg"> Confirm Action </button> </div> ); }
High-contrast edges are particularly significant for reducing confusion on interactive controls, ensuring they remain accessible to all users regardless of vision conditions.