Tailwind CSS Line Clamp
Line Clamp is used to truncate overflowed text to a specific number of lines, followed by an ellipsis (...
). This is particularly useful for creating concise content previews or ensuring text doesn't overflow its designated boundaries.
Tailwind CSS simplifies this implementation by providing a wide range of utility-first classes for managing line clamping. Let’s break down everything you need to know about leveraging this feature effectively in your projects.
Class | Properties | Example |
---|---|---|
line-clamp-1 | overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1; | <div className="line-clamp-1"></div> |
line-clamp-2 | overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2; | <div className="line-clamp-2"></div> |
line-clamp-3 | overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3; | <div className="line-clamp-3"></div> |
line-clamp-4 | overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 4; | <div className="line-clamp-4"></div> |
line-clamp-5 | overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 5; | <div className="line-clamp-5"></div> |
line-clamp-6 | overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 6; | <div className="line-clamp-6"></div> |
line-clamp-none | overflow: visible;
display: block;
-webkit-box-orient: horizontal;
-webkit-line-clamp: none; | <div className="line-clamp-none"></div> |
Overview of Line Clamp
Multi-line Text Truncation
Truncating your text to fit within a limited area improves user experience when handling long content. In Tailwind CSS, the line-clamp
utilities allow you to truncate multi-line text with simple configurations.
export default function MultiLineClamp() { return ( <div className="h-screen w-screen flex items-center justify-center bg-gray-100"> <div className="max-w-xs h-80 p-4 bg-white shadow-md rounded-md"> <img className="w-full h-48 object-cover rounded-t-md" src="https://images.unsplash.com/photo-1508873699372-7aeab60b44ab" alt="Content preview" /> <p className="line-clamp-4 text-gray-800 mt-3"> Tailwind CSS provides utility-first classes designed to simplify crafting web interfaces. Here, we demonstrate how line clamping works in a real-world card layout. Using the `line-clamp-4` utility, the paragraph truncates to three lines, ensuring consistent designs while enhancing readability and aesthetics. </p> </div> </div> ); }
Removing Line Limitations
Sometimes, you’ll find the need to revert clamping behavior to display full content. Tailwind makes undoing line clamping just as easy. To achieve this, add the line-clamp-none
class or apply the utility dynamically using conditional rendering.
export default function DynamicClamp() { const showFullText = true; // toggle this flag for different behavior return ( <div className="h-screen w-screen flex items-center justify-center"> <div className="max-w-sm p-6"> <p className={showFullText ? "text-gray-900 line-clamp-none" : "line-clamp-6 text-gray-700"}> Tailwind’s line clamping is incredibly flexible for scenarios where dynamic behavior is required. Flip the `showFullText` flag to see how clamping can be toggled off or on based on interaction preferences. This approach also minimizes the repetitive configuration of CSS or JavaScript. </p> </div> </div> ); }
States and Responsiveness
Hover and Focus States
Tailwind allows you to conditionally apply the utility class 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:line-clamp-none
.
export default function ClampOnHover() { return ( <div className="h-screen w-screen flex items-center justify-center"> <div className="max-w-md p-4"> <p className="line-clamp-2 hover:line-clamp-none transition-all"> Hover over this text to dynamically expand the content. Tailwind allows you to seamlessly integrate state-based modifiers across styles—for instance, removing line truncation when users hover over the paragraph, providing full contextual visibility. </p> </div> </div> ); }
Breakpoint Modifiers
Tailwind CSS provides breakpoint modifiers to conditionally apply the utility only when the screen hits the defined breakpoint. This is especially helpful for applying effects only on specific screens. Use Tailwind's breakpoint modifiers like- sm
, md
, etc., to apply the line clamp utilities only on the defined breakpoint and above.
export default function ResponsiveClamp() { return ( <div className="h-screen w-screen flex items-center justify-center p-4"> <p className="text-lg sm:line-clamp-1 md:line-clamp-2 lg:line-clamp-4"> "At smaller breakpoints, this text is restricted to one line, allowing critical information to take precedence. As the viewport grows, more lines gradually become visible, improving user engagement without sacrificing layout integrity or effectiveness on larger screens." </p> </div> ); }
Custom Line Clamp
When the built-in utilities aren’t sufficient for your design requirements, you can define custom line clamp by extending Tailwind’s configuration file.
Extending the Theme
The tailwind.config.js
file allows you to add custom line clamp utilities. Once added, these utilities are available globally and can be used as follows:
import tailwindConfig from "./tailwind.config.js"; tailwind.config = tailwindConfig; export default function CustomClamp() { return ( <div className="h-screen w-screen flex justify-center items-center p-6"> <p className="line-clamp-7"> With the custom `lineClamp` value in your Tailwind config, you're equipped to define unique truncation rules that go beyond defaults. Experiment with values that align with your design needs, all while maintaining Tailwind's renowned utility-first approach! This paragraph will not exceed the 7th line. </p> </div> ); }
Using Arbitrary Values
When you want to tweak your project on the go without defining the utilities in the theme file, use Tailwind’s arbitrary values:
export default function ArbitraryClamp() { return ( <div className="h-screen w-screen flex items-center justify-center p-5"> <p className="line-clamp-[4] text-center"> Tailwind’s arbitrary styles empower you to assign custom line-clamp values directly in class names. This approach removes the dependency on additional configuration steps while keeping your design logic flexible and application-ready. </p> </div> ); }
Real World Examples
Blog Post Cards
This example shows how to create a grid of blog post previews with line-clamped descriptions. Perfect for content-heavy websites where you need to display multiple blog posts in a clean, uniform layout.
export default function BlogPreviewGrid() { const blogPosts = [ { id: 1, title: "Understanding Modern JavaScript Development", description: "Explore the latest features in JavaScript ES2022, including top-level await, RegExp match indices, and new class elements. Learn how these additions can improve your code quality and development workflow in practical applications.", image: "https://images.unsplash.com/photo-1627398242454-45a1465c2479", author: "Sarah Chen", date: "2023-10-15" }, { id: 2, title: "Building Scalable Microservices Architecture", description: "Deep dive into microservices architecture patterns, service discovery, load balancing, and fault tolerance. Understand how to design resilient distributed systems that can handle millions of requests.", image: "https://images.unsplash.com/photo-1623479322729-28b25c16b011", author: "Mike Johnson", date: "2023-10-14" }, // ... Add 4 more similar items ]; return ( <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 p-6"> {blogPosts.map((post) => ( <div key={post.id} className="bg-white rounded-lg shadow-md overflow-hidden"> <img src={post.image} alt={post.title} className="w-full h-48 object-cover" /> <div className="p-4"> <h3 className="text-xl font-bold line-clamp-1">{post.title}</h3> <p className="text-gray-600 mt-2 line-clamp-3">{post.description}</p> <div className="mt-4 flex justify-between items-center"> <span className="text-sm text-gray-500">{post.author}</span> <span className="text-sm text-gray-500">{post.date}</span> </div> </div> </div> ))} </div> ); }
E-commerce Cards
This example demonstrates how to create product cards with clamped descriptions for an e-commerce platform.
export default function ProductGrid() { const products = [ { id: 1, name: "Premium Wireless Headphones", description: "Experience crystal-clear audio with our premium wireless headphones. Features active noise cancellation, 40-hour battery life, and premium leather cushions for maximum comfort during extended listening sessions.", price: 299.99, image: "https://images.unsplash.com/photo-1505740420928-5e560c06d30e", rating: 4.8, reviews: 256 }, // ... Add 5 more products ]; return ( <div className="bg-gray-100 p-8"> <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8"> {products.map((product) => ( <div key={product.id} className="bg-white rounded-xl p-6 shadow-lg"> <div className="relative aspect-square mb-4"> <img src={product.image} alt={product.name} className="absolute w-full h-full object-cover rounded-lg" /> </div> <h3 className="text-lg font-semibold line-clamp-1">{product.name}</h3> <p className="text-gray-600 mt-2 text-sm line-clamp-2"> {product.description} </p> <div className="mt-4 flex justify-between items-center"> <span className="text-2xl font-bold">${product.price}</span> <div className="flex items-center"> <span className="text-yellow-400">★</span> <span className="ml-1 text-sm">{product.rating}</span> <span className="ml-1 text-sm text-gray-500"> ({product.reviews}) </span> </div> </div> </div> ))} </div> </div> ); }
News Feed
This example shows a news feed with expandable content using a "Show More" button.
export default function NewsFeed() { const newsItems = [ { id: 1, title: "Breaking: Major Technology Breakthrough", content: "Scientists have achieved a groundbreaking discovery in quantum computing, potentially revolutionizing the way we process information. The new quantum processor can perform calculations in microseconds that would take traditional computers thousands of years to complete. This development could have far-reaching implications for cryptography, drug discovery, and climate modeling.", image: "https://images.unsplash.com/photo-1518770660439-4636190af475", source: "Tech Weekly", timestamp: "2 hours ago" }, // ... Add 5 more news items ]; return ( <div className="max-w-3xl mx-auto p-4"> {newsItems.map((item) => ( <div key={item.id} className="mb-8 bg-white rounded-lg shadow-md overflow-hidden"> <img src={item.image} alt={item.title} className="w-full h-64 object-cover" /> <div className="p-6"> <h2 className="text-2xl font-bold mb-2 line-clamp-2">{item.title}</h2> <p className="text-gray-700 line-clamp-3 mb-4">{item.content}</p> <button className="text-blue-600 hover:underline"> Read More </button> <div className="mt-4 flex items-center text-sm text-gray-500"> <span>{item.source}</span> <span className="mx-2">•</span> <span>{item.timestamp}</span> </div> </div> </div> ))} </div> ); }
Team Member Directory
This example demonstrates a team member directory with clamped bios.
export default function TeamDirectory() { const teamMembers = [ { id: 1, name: "Dr. Alexandra Thompson", role: "Chief Technology Officer", bio: "Dr. Thompson has over 15 years of experience in software architecture and machine learning. She previously led AI initiatives at major tech companies and has published numerous papers on distributed systems and neural networks. She holds a Ph.D. in Computer Science from Stanford University.", image: "https://images.unsplash.com/photo-1438761681033-6461ffad8d80", contact: "alexandra.t@company.com" }, // ... Add 5 more team members ]; return ( <div className="bg-gray-50 p-8"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8"> {teamMembers.map((member) => ( <div key={member.id} className="bg-white rounded-lg shadow-md p-6"> <div className="flex flex-col items-center"> <img src={member.image} alt={member.name} className="w-32 h-32 rounded-full object-cover mb-4" /> <h3 className="text-xl font-semibold text-center line-clamp-1"> {member.name} </h3> <p className="text-blue-600 mb-2">{member.role}</p> <p className="text-gray-600 text-center line-clamp-4"> {member.bio} </p> <button className="mt-4 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700"> Contact </button> </div> </div> ))} </div> </div> ); }
Recipe Card Gallery
This example shows a gallery of recipe cards with clamped ingredients and instructions.
export default function RecipeGallery() { const recipes = [ { id: 1, title: "Mediterranean Quinoa Bowl", description: "A healthy and delicious bowl packed with protein and fresh vegetables", image: "https://images.unsplash.com/photo-1512621776951-a57141f2eefd", prepTime: "20 mins", cookTime: "15 mins", ingredients: "Quinoa, Cherry Tomatoes, Cucumber, Kalamata Olives, Feta Cheese, Red Onion, Extra Virgin Olive Oil, Lemon Juice, Fresh Herbs", instructions: "1. Cook quinoa according to package instructions. 2. Chop all vegetables. 3. Mix vegetables with cooked quinoa. 4. Add crumbled feta cheese. 5. Drizzle with olive oil and lemon juice. 6. Season with salt and pepper to taste.", difficulty: "Easy", servings: 4 }, // ... Add 5 more recipes ]; return ( <div className="bg-white p-6"> <div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-8"> {recipes.map((recipe) => ( <div key={recipe.id} className="border rounded-xl overflow-hidden shadow-lg"> <img src={recipe.image} alt={recipe.title} className="w-full h-64 object-cover" /> <div className="p-6"> <h3 className="text-xl font-bold mb-2 line-clamp-1"> {recipe.title} </h3> <p className="text-gray-600 mb-4 line-clamp-2"> {recipe.description} </p> <div className="mb-4"> <h4 className="font-semibold mb-1">Ingredients:</h4> <p className="text-gray-600 text-sm line-clamp-2"> {recipe.ingredients} </p> </div> <div className="mb-4"> <h4 className="font-semibold mb-1">Instructions:</h4> <p className="text-gray-600 text-sm line-clamp-3"> {recipe.instructions} </p> </div> <div className="flex justify-between text-sm text-gray-500"> <span>Prep: {recipe.prepTime}</span> <span>Cook: {recipe.cookTime}</span> <span>Serves: {recipe.servings}</span> </div> </div> </div> ))} </div> </div> ); }
Customization Examples
Blog Post Card
This example demonstrates a blog post card with a custom line clamp for the excerpt, configured through the theme.
import tailwindConfig from "./tailwind.config.js"; tailwind.config = tailwindConfig; // App.js export default function BlogCard() { return ( <div className="max-w-md mx-auto bg-white rounded-xl shadow-md overflow-hidden"> <div className="md:flex"> <div className="p-8"> <img src="https://images.unsplash.com/photo-1498050108023-c5249f4df085" alt="Coding" className="w-full h-48 object-cover rounded-lg" /> <div className="uppercase tracking-wide text-sm text-indigo-500 font-semibold mt-4"> Technology </div> <h2 className="block mt-1 text-xl font-medium text-black"> Understanding the Fundamentals of Modern Web Development and Its Impact on Future Technologies </h2> <p className="mt-2 text-gray-500 line-clamp-blog-excerpt"> Explore the core concepts of web development, from responsive design to progressive enhancement. Learn how modern frameworks are shaping the future of web applications and why understanding these principles is crucial for every developer in today's digital landscape. </p> </div> </div> </div> ) }
Product Card
This example shows a product card with an expandable description using custom line clamp values.
import tailwindConfig from "./tailwind.config.js"; tailwind.config = tailwindConfig; // App.js import { useState } from 'react' export default function ProductCard() { const [isExpanded, setIsExpanded] = useState(false) return ( <div className="max-w-sm mx-auto bg-white rounded-lg shadow-lg p-6"> <img src="https://images.unsplash.com/photo-1542291026-7eec264c27ff" alt="Product" className="w-full h-64 object-cover rounded-md" /> <h2 className="text-2xl font-bold mt-4">Premium Running Shoes</h2> <div className="mt-2"> <p className={`text-gray-600 ${isExpanded ? '' : 'line-clamp-product'}`}> Experience ultimate comfort with our revolutionary cushioning technology. These premium running shoes feature advanced moisture-wicking materials, ergonomic design for optimal support, and durable construction for long-lasting performance. The innovative sole design provides superior grip on various surfaces, while the breathable mesh upper ensures proper ventilation during intense workouts. </p> <button onClick={() => setIsExpanded(!isExpanded)} className="mt-2 text-blue-600 hover:text-blue-800 font-medium" > {isExpanded ? 'Show Less' : 'Read More'} </button> </div> </div> ) }
News Feed
This example implements a news feed with different line clamp values for different screen sizes.
import tailwindConfig from "./tailwind.config.js"; tailwind.config = tailwindConfig; // App.js export default function NewsFeed() { const newsItems = [ { title: "Breaking Technology News", image: "https://images.unsplash.com/photo-1519389950473-47ba0277781c", content: "In a groundbreaking development, researchers have announced a major breakthrough in quantum computing technology. The new discovery promises to revolutionize the way we process information, potentially solving complex problems that were previously impossible to tackle with traditional computing methods. This advancement could have far-reaching implications for cryptography, drug discovery, and climate modeling." }, { title: "Industry Updates", image: "https://images.unsplash.com/photo-1451187580459-43490279c0fa", content: "Major tech companies are joining forces to establish new standards for artificial intelligence development. This collaborative effort aims to ensure responsible AI growth while addressing concerns about ethics and safety. The initiative will focus on creating transparent guidelines for AI deployment across various sectors." } ] return ( <div className="max-w-2xl mx-auto space-y-6 p-4"> {newsItems.map((item, index) => ( <div key={index} className="bg-white rounded-xl shadow-lg overflow-hidden"> <img src={item.image} alt={item.title} className="w-full h-48 object-cover" /> <div className="p-6"> <h3 className="text-xl font-bold text-gray-900 mb-2"> {item.title} </h3> <p className="text-gray-600 line-clamp-mobile md:line-clamp-tablet lg:line-clamp-desktop"> {item.content} </p> </div> </div> ))} </div> ) }
Best Practices
Maintain Design Consistency
Keeping line clamp styles consistent across similar components, such as cards, tooltips, or list items, maintains a polished and predictable design. Inconsistent application may result in some sections appearing visually disconnected from the rest of the interface. To enforce consistency, define a standardized set of line-clamp-*
values in your design system and ensure they are applied to components with similar roles.
Complement line clamp with font size, line height and letter spacing utilities to define how truncated text appears. This helps in retaining readability and uniformity, allowing for a more structured presentation of clamped content.
Leverage Utility Combinations
When using Tailwind’s line-clamp-*
utilities, pairing it with whitespace-*
and break-*
utilities can prevent text from breaking unexpectedly. This is particularly useful when handling dynamic or user-generated content where strict clamping is necessary to maintain layout integrity. By controlling how text wraps and breaks, you can ensure a more predictable and visually consistent experience, even when working with varying content lengths.
For instance, using whitespace-nowrap
ensures that text remains on a single line before being truncated, while break-words
allows long words to break naturally rather than overflowing their container. These utilities, when combined with line clamp, prevent unintended overflow and preserve readability.
Accessibility Considerations
Enhance Readability and Navigability
Readability is a key aspect of accessibility, and applying line-clamp-*
should not hinder users from understanding content effectively. Since line clamp cuts the portions of the text, it’s important to ensure that users can access the full content in an intuitive manner. Implementing mechanisms such as tooltips, read-more links, or expanding elements can help users retrieve truncated information when needed.
It’s also helpful to avoid strict line clamp that makes comprehension difficult. Truncating text after just one or two lines may cut off essential details, leading to confusion. Whenever possible, prioritize using line-clamp-*
on secondary content rather than crucial instructions.
Focus on High Contrast
Contrast plays a vital role in ensuring that clamped text remains legible for users with visual impairments. When applying line-clamp-*
, ensure that the text color stands out against its background. For example, the use of text-gray-900
on light backgrounds or text-white
on dark backgrounds ensures sufficient contrast, making clamped text easier to read.
Additionally, avoiding background images or busy patterns behind clamped text prevents readability issues. If using a background image, apply bg-opacity-*
or backdrop-brightness-*
to maintain sufficient text contrast without compromising visibility. Pairing line-clamp-*
with appropriate font weights also enhances readability, making text clearer for all users.