Tailwind CSS Text Overflow
Text overflow in CSS determines how text is displayed when it overflows the boundaries of its container. Without text overflow properties, overflowing text can break designs, making UIs look cluttered or non-functional. The CSS properties text-overflow
, white-space
, and overflow
are commonly used together to achieve specific text display behavior like truncation or ellipsis.
Tailwind CSS provides a concise set of utility classes to manage text overflow behavior effectively, eliminating the need for manually writing CSS for these aspects. With Tailwind, you can apply these utilities using predefined classes for truncation, ellipsis, or clipping.
Class | Properties | Example |
---|---|---|
truncate | overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap; | <div className="truncate"></div> |
text-ellipsis | text-overflow: ellipsis; | <div className="text-ellipsis"></div> |
text-clip | text-overflow: clip; | <div className="text-clip"></div> |
Overview of Text Overflow
To enable clipping, truncation, or specific text behavior, you can use the following predefined utilities:
Applying Truncate
Truncation allows text to gracefully shorten when it overflows its container. It removes the overflow characters and replaces them with an ellipsis (...
). This is beneficial for single-line UI elements like cards or buttons, where preserving the layout is critical.
// Tailwind CSS Container with Truncation export default function TruncatedText() { return ( <div className="h-screen w-screen bg-gray-100 flex justify-center items-center"> <p className="truncate w-64 border border-gray-200 bg-white p-4 text-black"> This sentence will be truncated at the end. </p> </div> ); } // Tailwind styles: truncate => overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
Applying Ellipsis
This approach ensures any overflowed text is completely hidden and replaced with an ellipsis. It's often used in more complex multi-line situations.
// Using "text-ellipsis" Tailwind CSS export default function EllipsisText() { return ( <div className="h-screen w-screen bg-gray-100 flex justify-center items-center"> <p className="text-ellipsis overflow-hidden w-64 border border-gray-200 bg-white p-4 text-black"> Inthisparagraph,onlytheoverflowedtext will be clipped towards the end of its line. </p> </div> ); } // Tailwind generated properties: // text-ellipsis => text-overflow: ellipsis;
Applying Clip
For scenarios where simplicity matters, you can clip the overflowing content without adding the ellipsis upto the limit of the content area:
// Using "text-ellipsis" Tailwind CSS export default function ClippedText() { return ( <div className="h-screen w-screen bg-gray-100 flex justify-center items-center"> <p className="text-clip overflow-hidden w-64 border border-gray-200 bg-white p-4 text-black"> Inthisparagraph,theoverflowedtext will be clipped but ellipsis will not be used. </p> </div> ); } // Tailwind generated properties: // text-ellipsis => text-overflow: ellipsis;
Real World Examples
Product Cards with Long Descriptions
This example shows how to handle long product descriptions in an e-commerce grid layout with text overflow.
export default function ProductGrid() { const products = [ { id: 1, name: "Professional DSLR Camera with 4K Recording", description: "High-end professional camera with advanced features including 4K video recording, 45MP sensor, and weather-sealed body perfect for outdoor photography.", image: "https://images.unsplash.com/photo-1516035069371-29a1b244cc32", price: "$1,299.99" }, { id: 2, name: "Wireless Noise-Cancelling Headphones", description: "Premium wireless headphones featuring active noise cancellation, 30-hour battery life, and studio-quality sound reproduction.", image: "https://images.unsplash.com/photo-1505740420928-5e560c06d30e", price: "$349.99" }, { id: 3, name: "Smart Fitness Watch Pro", description: "Advanced fitness tracker with heart rate monitoring, GPS, sleep tracking, and 20+ sport modes.", image: "https://images.unsplash.com/photo-1579586337278-3befd40fd17a", price: "$199.99" }, { id: 4, name: "Ultra-Slim Laptop 15\"", description: "Powerful laptop featuring 11th gen processor, 16GB RAM, 512GB SSD, and stunning 4K display.", image: "https://images.unsplash.com/photo-1496181133206-80ce9b88a853", price: "$1,499.99" }, { id: 5, name: "Wireless Gaming Mouse", description: "High-precision gaming mouse with 25,000 DPI sensor, programmable buttons, and RGB lighting.", image: "https://images.unsplash.com/photo-1527864550417-7fd91fc51a46", price: "$79.99" } ]; 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-lg overflow-hidden"> <img src={product.image} alt={product.name} className="w-full h-48 object-cover" /> <div className="p-4"> <h3 className="font-bold text-lg truncate">{product.name}</h3> <p className="text-gray-600 mt-2 line-clamp-2 overflow-ellipsis"> {product.description} </p> <p className="text-blue-600 font-bold mt-2">{product.price}</p> </div> </div> ))} </div> ); }
News Article List with Dynamic Content
This example demonstrates how to handle varying lengths of news article titles and excerpts.
export default function NewsList() { const articles = [ { id: 1, title: "Breaking: Revolutionary New Technology Changes the Future of Renewable Energy", excerpt: "Scientists discover groundbreaking method to harness solar energy with unprecedented efficiency, promising to revolutionize sustainable power generation.", image: "https://images.unsplash.com/photo-1497435334941-8c899ee9e8e9", author: "Dr. Sarah Johnson", date: "2024-02-15" }, { id: 2, title: "Global Economy Faces New Challenges Amid Technological Disruption", excerpt: "Economic experts analyze the impact of artificial intelligence and automation on traditional industries and employment patterns.", image: "https://images.unsplash.com/photo-1611974789855-9c2a0a7236a3", author: "Michael Chang", date: "2024-02-14" }, { id: 3, title: "Space Exploration Milestone: First Human Settlement on Mars Planned", excerpt: "Leading space agencies announce collaborative effort to establish permanent human presence on Mars by 2040.", image: "https://images.unsplash.com/photo-1614728263952-84ea256f9679", author: "Alexandra Peters", date: "2024-02-13" }, { id: 4, title: "Breakthrough in Medical Research: New Treatment for Chronic Diseases", excerpt: "Researchers develop innovative therapy combining genetic engineering and targeted drug delivery systems.", image: "https://images.unsplash.com/photo-1576091160399-112ba8d25d1d", author: "Dr. James Wilson", date: "2024-02-12" }, { id: 5, title: "Environmental Crisis: Ocean Cleanup Initiative Shows Promise", excerpt: "International coalition launches largest-ever ocean cleanup project using advanced autonomous systems.", image: "https://images.unsplash.com/photo-1484291470158-b8f8d608850d", author: "Emma Rodriguez", date: "2024-02-11" }, { id: 6, title: "Digital Privacy Concerns Rise as New Security Threats Emerge", excerpt: "Cybersecurity experts warn of sophisticated new methods of data breach and recommend enhanced protection measures.", image: "https://images.unsplash.com/photo-1563986768609-322da13575f3", author: "Thomas Anderson", date: "2024-02-10" } ]; return ( <div className="max-w-4xl mx-auto p-6"> {articles.map((article) => ( <div key={article.id} className="mb-8 bg-white rounded-lg shadow-md overflow-hidden"> <div className="md:flex"> <div className="md:w-1/3"> <img src={article.image} alt={article.title} className="h-48 w-full object-cover" /> </div> <div className="p-6 md:w-2/3"> <h2 className="font-bold text-xl mb-2 truncate hover:text-clip hover:overflow-visible"> {article.title} </h2> <p className="text-gray-600 line-clamp-2 mb-4"> {article.excerpt} </p> <div className="flex justify-between text-sm text-gray-500"> <span>{article.author}</span> <span>{article.date}</span> </div> </div> </div> </div> ))} </div> ); }
User Profile Cards with Bio Overflow
This example shows how to handle user profile information with varying lengths of bio text.
export default function UserProfiles() { const users = [ { id: 1, name: "Emma Thompson", role: "Senior UX Designer", bio: "Award-winning designer with 10+ years of experience in creating user-centered digital experiences for global brands. Specialized in mobile app design and accessibility.", avatar: "https://images.unsplash.com/photo-1494790108377-be9c29b29330", location: "San Francisco, CA" }, { id: 2, name: "James Wilson", role: "Full Stack Developer", bio: "Passionate about building scalable web applications and mentoring junior developers. Expert in React, Node.js, and cloud architecture.", avatar: "https://images.unsplash.com/photo-1500648767791-00dcc994a43e", location: "London, UK" }, { id: 3, name: "Sophie Chen", role: "Product Manager", bio: "Strategic product leader with experience in launching successful SaaS products. Focus on data-driven decision making and user engagement.", avatar: "https://images.unsplash.com/photo-1438761681033-6461ffad8d80", location: "Singapore" }, { id: 4, name: "Marcus Johnson", role: "Marketing Director", bio: "Digital marketing strategist specializing in growth hacking and conversion optimization. Previously led marketing teams at several Fortune 500 companies.", avatar: "https://images.unsplash.com/photo-1472099645785-5658abf4ff4e", location: "New York, NY" }, { id: 5, name: "Lisa Rodriguez", role: "Data Scientist", bio: "PhD in Machine Learning with expertise in predictive modeling and natural language processing. Published researcher and conference speaker.", avatar: "https://images.unsplash.com/photo-1487412720507-e7ab37603c6f", location: "Toronto, Canada" }, { id: 6, name: "Alex Kumar", role: "UI Developer", bio: "Creative developer focusing on building beautiful and performant user interfaces. Advocate for web accessibility and responsive design.", avatar: "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d", location: "Berlin, Germany" } ]; return ( <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 p-6"> {users.map((user) => ( <div key={user.id} className="bg-white rounded-xl shadow-lg p-6"> <div className="flex items-center space-x-4"> <img src={user.avatar} alt={user.name} className="w-16 h-16 rounded-full object-cover" /> <div className="flex-1 min-w-0"> <h2 className="text-lg font-bold truncate">{user.name}</h2> <p className="text-sm text-gray-500 truncate">{user.role}</p> </div> </div> <div className="mt-4"> <p className="text-gray-600 line-clamp-3 hover:line-clamp-none transition-all duration-300"> {user.bio} </p> </div> <div className="mt-4 flex items-center text-sm text-gray-500"> <svg className="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" /> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" /> </svg> <span className="truncate">{user.location}</span> </div> </div> ))} </div> ); }
Recipe Cards with Ingredient Lists
This example demonstrates how to handle long lists of ingredients and instructions in recipe cards.
export default function RecipeGrid() { const recipes = [ { id: 1, title: "Mediterranean Quinoa Bowl", description: "A healthy and flavorful bowl packed with protein and fresh vegetables", image: "https://images.unsplash.com/photo-1512621776951-a57141f2eefd", ingredients: ["Quinoa", "Cherry Tomatoes", "Cucumber", "Kalamata Olives", "Feta Cheese", "Red Onion", "Extra Virgin Olive Oil", "Fresh Lemon Juice", "Garlic", "Mediterranean Herbs"], prepTime: "25 mins", difficulty: "Easy" }, { id: 2, title: "Spicy Thai Basil Chicken", description: "Classic Thai street food dish with aromatic basil and chili", image: "https://images.unsplash.com/photo-1455619452474-d2be8b1e70cd", ingredients: ["Chicken Thighs", "Thai Basil", "Garlic", "Thai Chilies", "Soy Sauce", "Fish Sauce", "Oyster Sauce", "Sugar", "Green Beans", "Red Bell Pepper"], prepTime: "30 mins", difficulty: "Medium" }, { id: 3, title: "Homemade Pizza Margherita", description: "Traditional Italian pizza with fresh mozzarella and basil", image: "https://images.unsplash.com/photo-1513104890138-7c749659a591", ingredients: ["Pizza Dough", "San Marzano Tomatoes", "Fresh Mozzarella", "Fresh Basil", "Extra Virgin Olive Oil", "Sea Salt", "Black Pepper", "Garlic", "Oregano"], prepTime: "45 mins", difficulty: "Medium" }, { id: 4, title: "Vegetarian Buddha Bowl", description: "Nutrient-rich bowl with roasted vegetables and tahini dressing", image: "https://images.unsplash.com/photo-1540420773420-3366772f4999", ingredients: ["Sweet Potato", "Chickpeas", "Kale", "Quinoa", "Avocado", "Tahini", "Lemon Juice", "Maple Syrup", "Red Cabbage", "Pumpkin Seeds"], prepTime: "40 mins", difficulty: "Easy" }, { id: 5, title: "Classic French Onion Soup", description: "Rich and comforting soup topped with melted Gruyère cheese", image: "https://images.unsplash.com/photo-1547592180-85f173990554", ingredients: ["Yellow Onions", "Beef Broth", "White Wine", "Butter", "Gruyère Cheese", "Baguette", "Thyme", "Bay Leaves", "Garlic", "Black Pepper"], prepTime: "1 hour 15 mins", difficulty: "Medium" }, { id: 6, title: "Mango Coconut Chia Pudding", description: "Tropical breakfast pudding with fresh fruits and nuts", image: "https://images.unsplash.com/photo-1511690656952-34342bb7c2f2", ingredients: ["Chia Seeds", "Coconut Milk", "Fresh Mango", "Honey", "Vanilla Extract", "Almonds", "Coconut Flakes", "Fresh Mint", "Dragon Fruit", "Passion Fruit"], prepTime: "15 mins + overnight", difficulty: "Easy" } ]; return ( <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 p-8"> {recipes.map((recipe) => ( <div key={recipe.id} className="bg-white rounded-2xl shadow-lg overflow-hidden"> <img src={recipe.image} alt={recipe.title} className="w-full h-48 object-cover" /> <div className="p-6"> <h2 className="font-bold text-xl mb-2 truncate"> {recipe.title} </h2> <p className="text-gray-600 mb-4 line-clamp-2"> {recipe.description} </p> <div className="mb-4"> <h3 className="font-semibold text-sm mb-2">Ingredients:</h3> <div className="flex flex-wrap gap-2"> {recipe.ingredients.map((ingredient, index) => ( <span key={index} className="bg-gray-100 text-gray-700 text-xs px-2 py-1 rounded-full truncate max-w-[150px]" > {ingredient} </span> ))} </div> </div> <div className="flex justify-between text-sm text-gray-500"> <span>⏱ {recipe.prepTime}</span> <span>📊 {recipe.difficulty}</span> </div> </div> </div> ))} </div> ); }
Project Timeline Cards
This example shows how to handle project timeline entries with varying content lengths.
export default function ProjectTimeline() { const projects = [ { id: 1, title: "E-commerce Platform Redesign", description: "Complete overhaul of the existing e-commerce platform with focus on mobile responsiveness and checkout optimization.", status: "Completed", date: "2024-02-15", team: ["UI Designer", "Frontend Dev", "Backend Dev", "PM"], image: "https://images.unsplash.com/photo-1460925895917-afdab827c52f", updates: ["Initial wireframes completed", "User testing phase", "Final deployment", "Performance optimization"] }, { id: 2, title: "Mobile App Development", description: "Development of a cross-platform mobile application for fitness tracking and social networking.", status: "In Progress", date: "2024-03-01", team: ["Mobile Dev", "UX Designer", "Backend Dev"], image: "https://images.unsplash.com/photo-1551650975-87deedd944c3", updates: ["Framework selection", "UI design approval", "Backend API development"] }, { id: 3, title: "Cloud Infrastructure Migration", description: "Migration of legacy systems to cloud infrastructure with focus on scalability and security.", status: "Planning", date: "2024-04-01", team: ["Cloud Architect", "DevOps", "Security Engineer"], image: "https://images.unsplash.com/photo-1451187580459-43490279c0fa", updates: ["Initial assessment", "Architecture planning", "Security review"] }, { id: 4, title: "Data Analytics Dashboard", description: "Development of real-time analytics dashboard for business intelligence and reporting.", status: "In Review", date: "2024-02-28", team: ["Data Scientist", "Frontend Dev", "UI Designer"], image: "https://images.unsplash.com/photo-1551288049-bebda4e38f71", updates: ["Data modeling", "Dashboard prototyping", "Integration testing"] }, { id: 5, title: "Customer Support Portal", description: "Implementation of self-service customer support portal with AI-powered chatbot integration.", status: "On Hold", date: "2024-05-15", team: ["Frontend Dev", "AI Engineer", "UX Designer"], image: "https://images.unsplash.com/photo-1553877522-43269d4ea984", updates: ["Requirements gathering", "Chatbot training", "Interface design"] }, { id: 6, title: "Security Compliance Update", description: "Implementation of enhanced security measures and compliance updates across all systems.", status: "Starting Soon", date: "2024-03-15", team: ["Security Engineer", "Compliance Officer", "System Admin"], image: "https://images.unsplash.com/photo-1563986768494-4dee2763ff3f", updates: ["Audit planning", "Policy review", "Training preparation"] } ]; return ( <div className="max-w-5xl mx-auto p-6"> <div className="space-y-6"> {projects.map((project) => ( <div key={project.id} className="bg-white rounded-lg shadow-lg overflow-hidden"> <div className="md:flex"> <div className="md:w-1/4"> <img src={project.image} alt={project.title} className="h-full w-full object-cover" /> </div> <div className="p-6 md:w-3/4"> <div className="flex justify-between items-start"> <h2 className="font-bold text-xl mb-2 truncate"> {project.title} </h2> <span className={`px-3 py-1 rounded-full text-sm ${ project.status === "Completed" ? "bg-green-100 text-green-800" : project.status === "In Progress" ? "bg-blue-100 text-blue-800" : "bg-gray-100 text-gray-800" }`}> {project.status} </span> </div> <p className="text-gray-600 mb-4 line-clamp-2"> {project.description} </p> <div className="space-y-4"> <div> <h3 className="text-sm font-semibold mb-2">Team:</h3> <div className="flex flex-wrap gap-2"> {project.team.map((member, index) => ( <span key={index} className="bg-gray-100 text-gray-700 text-xs px-2 py-1 rounded-full truncate" > {member} </span> ))} </div> </div> <div> <h3 className="text-sm font-semibold mb-2">Recent Updates:</h3> <ul className="text-sm text-gray-600 list-disc list-inside"> {project.updates.map((update, index) => ( <li key={index} className="truncate"> {update} </li> ))} </ul> </div> </div> <div className="mt-4 text-sm text-gray-500"> Due: {project.date} </div> </div> </div> </div> ))} </div> </div> ); }
Best Practices
Maintain Design Consistency
By aligning overflow utilities with existing design standards in your project, such as established spacing, typography, and font sizes, you create a professional interface that feels intuitive to users. Uniformity is particularly critical when dealing with dynamic content like user-generated text or API responses.
Use truncate
, text-ellipsis
, or text-clip
strategically within specified contexts. For instance, complex components like news headlines may require text-ellipsis
paired with overflow-hidden
to establish multi-line control.
Leverage Utility Combinations
Effective designs often combine multiple utilities to achieve an integrated result. By layering Tailwind utilities like truncate
, hover:line-clamp-x
, or media query-based utilities such as lg:text-ellipsis
, you can fine-tune how Text Overflow interacts with responsive layout structures.
For effective multi-line truncation paired with scrolling behaviors, use Tailwind classes like line-clamp-3
wrapped within responsive breakpoints. For instance, you can enable scrolling for desktop users while restricting text within line clamping for mobile-friendly devices. These combinations ensure scalability.
Accessibility Considerations
Enhance Readability and Navigability
Text Overflow utilities like truncate
streamline readability on tight designs, but always balance accessibility through meaningful optimizations such as custom tooltips or alt content for elongated text. Pair overflow behavior class changes with aria-label
attributes where meaningful navigation or text expansion is essential.
Furthermore, use high contrast consistently for users requiring visual emphasis. Test overflow behaviors using screen readers for vocalized clarity of truncated segments.
Support Accessible Interactive Elements
Extend accessibility principles into interactivity scenarios, ensuring components like expand-on-hover/focus card sections expose content without user limitations. Integrate focus-visible
states ensuring keyboard reliance replicates mouse-hover ease, revealing truncated text inline.
Keyboard-enforced proactive navigation significantly improves engagement between visible and truncated hierarchies for better interactivity inclusiveness.