Menu

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.

ClassPropertiesExample
line-clamp-1overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 1;<div className="line-clamp-1"></div>
line-clamp-2overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;<div className="line-clamp-2"></div>
line-clamp-3overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3;<div className="line-clamp-3"></div>
line-clamp-4overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 4;<div className="line-clamp-4"></div>
line-clamp-5overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 5;<div className="line-clamp-5"></div>
line-clamp-6overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 6;<div className="line-clamp-6"></div>
line-clamp-noneoverflow: 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.

This is a live editor. Play around with it!
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.

This is a live editor. Play around with it!
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.

This is a live editor. Play around with it!
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.

This is a live editor. Play around with it!
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:

This is a live editor. Play around with it!
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:

This is a live editor. Play around with it!
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.

This is a live editor. Play around with it!
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.

This is a live editor. Play around with it!
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.

This is a live editor. Play around with it!
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.

This is a live editor. Play around with it!
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>
  );
}

This example shows a gallery of recipe cards with clamped ingredients and instructions.

This is a live editor. Play around with it!
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.

This is a live editor. Play around with it!
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.

This is a live editor. Play around with it!
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.

This is a live editor. Play around with it!
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.