When working with text-heavy web applications, you might come across scenarios where long text needs to be truncated after a certain number of lines. CSS properties like -webkit-line-clamp
make this easy by limiting the visible lines of text, but you might need to know when that text has been clamped for purposes like showing a “Read More” button or providing feedback to users. In this post, I’ll walk you through how to detect clamped text in a React component using JavaScript.
Thank me by sharing on Twitter 🙏
In this guide, I’ll explain what clamping is, how to detect clamped text in React, and how to implement this solution in your project.
Understanding Text Clamping
Clamping is the process of visually truncating content after a specific number of lines. For example, with -webkit-line-clamp
, you can restrict text to two or three lines, adding an ellipsis if the text is too long. This method is commonly used in scenarios like blog previews, product descriptions, or article summaries, where you want to maintain a clean layout by showing a limited amount of text.
Here’s an example of clamping text with CSS:
.clamped-text {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
}
In this CSS, the -webkit-line-clamp
property limits the number of visible lines to three. However, this truncation happens purely on the front end, and CSS doesn’t provide a way to check if the text has actually been truncated. That’s where JavaScript and React come into play.
The Art and Making of Arcane (Gaming)
$56.94 (as of December 21, 2024 19:39 GMT +00:00 - More infoProduct prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on [relevant Amazon Site(s), as applicable] at the time of purchase will apply to the purchase of this product.)Logitech M510 Wireless Computer Mouse for PC with USB Unifying Receiver - Graphite
$19.99 (as of December 21, 2024 08:38 GMT +00:00 - More infoProduct prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on [relevant Amazon Site(s), as applicable] at the time of purchase will apply to the purchase of this product.)Car Carplay Cable for iPhone 15 16 15 Pro Max 15 16 Plus Cable, USB A to USB C for Carplay USB C Cord, iPad USB C Cable iPad Pro iPad Air 5th 4th Mini 6th Gen Car Charger Cable Cord Replacement 3FT
$7.99 (as of December 21, 2024 08:38 GMT +00:00 - More infoProduct prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on [relevant Amazon Site(s), as applicable] at the time of purchase will apply to the purchase of this product.)The Challenge: Detecting Clamped Text in React
When working with React, you may want to know if a piece of text is clamped to display additional controls, like a “Show More” button, or to notify users that some of the content is hidden. Unfortunately, CSS alone doesn’t offer a way to detect clamped text. The good news is that JavaScript can do the job.
The basic idea is to compare the height of the element containing the text with the height of the fully expanded text. If the full height exceeds the visible height (i.e., the scrollHeight
is greater than the clientHeight
), the text is clamped.
Step 1: Setting Up the React Component
First, let’s create a simple React component to display some clamped text. We’ll use the useRef
hook to gain direct access to the DOM element, and useEffect
to check if the text is clamped when the component renders.
Here’s what the basic component looks like:
import React, { useEffect, useRef, useState } from 'react';
const ClampedText = ({ text }: { text: string }) => {
const textRef = useRef<HTMLDivElement>(null);
const [isClamped, setIsClamped] = useState(false);
useEffect(() => {
const checkClamping = () => {
const element = textRef.current;
if (element) {
const currentStyle = window.getComputedStyle(element);
const lineClamp = parseInt(currentStyle.getPropertyValue('-webkit-line-clamp'), 10);
if (lineClamp > 0 && currentStyle.getPropertyValue('overflow') === 'hidden') {
setIsClamped(element.scrollHeight > element.clientHeight);
} else {
setIsClamped(false);
}
}
};
checkClamping();
window.addEventListener('resize', checkClamping); // Handle resizing
return () => window.removeEventListener('resize', checkClamping);
}, [text]);
return (
<div>
<div
ref={textRef}
style={{
display: '-webkit-box',
WebkitLineClamp: 3,
WebkitBoxOrient: 'vertical',
overflow: 'hidden',
textOverflow: 'ellipsis',
}}
>
{text}
</div>
{isClamped && <p>Text is clamped</p>}
</div>
);
};
export default ClampedText;
Step 2: Breaking Down the Logic
Let’s walk through the key parts of this code:
Using useRef
to Access the DOM
In React, we can’t directly access DOM elements like we can with plain JavaScript. Instead, we use the useRef
hook to create a reference to the DOM element. The textRef
variable in this example holds a reference to the div that contains the text we want to clamp.
const textRef = useRef<HTMLDivElement>(null);
This allows us to interact with the underlying DOM element directly, which is crucial for checking its height later.
Checking Clamping with scrollHeight
and clientHeight
Next, in the checkClamping
function, we compare the scrollHeight
of the element to its clientHeight
. The scrollHeight
is the total height of the content inside the element, including any overflow. The clientHeight
is the visible height of the element. If the scrollHeight
exceeds the clientHeight
, it means the content is clamped.
if (element.scrollHeight > element.clientHeight) {
setIsClamped(true);
}
We also check if the -webkit-line-clamp
property is set to a positive value and if the overflow
is set to hidden
, as these are essential for clamping to occur.
Responding to Window Resize
Text clamping might behave differently depending on the size of the window. For example, reducing the width of the window may cause more clamping, while increasing the width may reduce it. To handle this, we add a resize event listener that re-checks whether the text is clamped when the window is resized.
window.addEventListener('resize', checkClamping);
This ensures that we can accurately detect when clamping changes based on the window size.
Step 3: Adding a User-Friendly Indicator
In this example, we render a simple <p>
element that informs the user when the text is clamped:
{isClamped && <p>Text is clamped</p>}
This conditional rendering ensures that the message only appears if the text is indeed clamped. You can easily modify this to display a “Read More” button or any other UI element you prefer.
Step 4: Testing the Component
With the component complete, you can test it by passing different lengths of text to see how it behaves. You’ll notice that the message changes based on whether the text fits within the specified number of lines or not.
For example:
<ClampedText text="This is a long text that might be clamped depending on the width of the container and the number of lines allowed." />
You can also modify the WebkitLineClamp
value in the component’s style
to adjust the number of lines before clamping occurs.
Conclusion
Detecting clamped text in a React application can be incredibly useful for improving user experience, especially when dealing with dynamic content. By using the scrollHeight
and clientHeight
properties, we can easily determine whether a piece of text is being truncated and take appropriate action, such as displaying a “Read More” button or informing the user that some content is hidden.
The approach outlined in this post provides a simple and effective way to handle clamped text in your React components. Whether you’re working with long blog posts, product descriptions, or any other type of text, this solution gives you full control over how clamping is detected and managed.