ChopLines is a lightweight React component which truncates multiple lines of HTML markup.
I found several React components which truncate plain text, but few that supported truncation of HTML, and none I was happy with. ChopLines solves the challenge by measuring its children and applying truncation for a given height or number of lines.
See it in action
Usage
Add the dependency:
yarn add chop-lines
And then in your component(s):
import ChopLines from 'chop-lines';
Prop | Requirement |
---|---|
lines | required if maxHeight is not set |
lineHeight | required if maxHeight is not set |
maxHeight | required if lines & linesHeight are not set |
ellipsis | Optional (default: "…") |
children | required |
Implementation Example
import React, { useState } from 'react';
import ChopLines from 'chop-lines';
import insane from 'insane';
import { Wrapper, Ellipsis } from './styles';
const Sanitized = ({ html }) => (
<div
dangerouslySetInnerHTML={{
__html: insane(html, {
allowedTags: ['p', 'strong', 'em', 'a'],
}),
}}
/>
);
const html = `
<p>
Lorem ipsum dolor sit amet, consectetur
adipiscing elit. Duis turpis nunc, feugiat
nec facilisis ac, pretium non erat.
<strong>
Pellentesque habitant morbi tristique
<a href="#">some link</a>
senectus et netus et malesuada fames ac
turpis egestas.
</strong>
<em>
Suspendisse a semper magna. Aenean rhoncus
eros non quam eleifend, vitae porttitor
odio bibendum.
</em>
</p>
`;
const ChopLinesExample = () => {
const [isExpanded, setIsExpanded] = useState(false);
const handleClick = () => setIsExpanded(true);
return (
<Wrapper>
{isExpanded ? (
<Sanitized html={html} />
) : (
<ChopLines
lines={3}
lineHeight={24}
ellipsis={
<Ellipsis onClick={handleClick}>
<span>Read More</span>
</Ellipsis>
}
>
<Sanitized html={html} />
</ChopLines>
)}
</Wrapper>
);
}
export default ChopLinesExample;
import styled from 'styled-components';
import { rem, position } from 'styled-tidy';
export const Wrapper = styled.div`
background: white;
color: darkslategrey;
font-size: ${rem(16)};
font-weight: 400;
max-width: ${rem(540)};
padding: ${rem(16)};
position: relative;
p a {
color: dodgerblue;
text-decoration: underline;
}
`;
export const Ellipsis = styled.a`
background: white;
font-size: ${rem(12)};
font-weight: 700;
outline: none;
text-transform: uppercase;
span {
background: lavender;
border-radius: ${rem(12)};
color: slateblue;
display: inline-block;
padding: 0 ${rem(8)};
}
:hover,
:focus {
span {
color: indigo;
}
}
:before {
${position('absolute', 0)}
background: linear-gradient(
90deg,
rgba(255,255,255,0),
white
);
content: '';
width: ${rem(48)};
}
`;