13

I'm trying to build a component with multiline textfield. If the text entered exceeds 2 lines, then I'd like to add the ellipsis (...) for text-overflow.

How can I achieve this by just manipulating the css to show the ellipsis in display only but not modify the actual text that will be stored to contain '...'?

I'm using this React component link

Thanks

veggirice
  • 246
  • 1
  • 2
  • 15
  • This is probably not possible with css, as I'm fairly sure there's no way to determine how many lines are in an area using css – OliverRadini Nov 05 '18 at 14:26

4 Answers4

28

I just figured out how to solve this for React.

As Khodor mentioned, line-clamp is what you want. However, it's not currently supported by the official CSS spec. So, you can use -webkit-line-clamp as a sort of workaround. However, I struggled to figure out the exact syntax needed for React. I eventually figured out it out by peeking at the source code for this NPM package react-lines-ellipses and searching for 'webkit' in his github repo.

The React-specific CSS

const textStyle = {
    maxWidth: '100%',
    display: '-webkit-box',
    WebkitBoxOrient: 'vertical',
    WebkitLineClamp: 3,
    overflow: 'hidden',
    textOverflow: 'ellipsis',
  };

I set the maxWidth to ensure the text filled the whole width of the display element. This is optional.

overflow: 'hidden' hides the extra text beyond the 3 lines (I chose 3 at random).

textOverflow: 'ellipses' adds an ellipses (...) to the end of the line, where it gets cut off.

The JSX

<div
    onClick={toggleTruncate}
    style={calculateTextStyle()}
>
This is where my long text goes.
</div>


// This function returns the correct style to the above div.
 function calculateTextStyle() {
    return truncate ? textStyle : null;
  }

// I used React Hooks to create a variable in state to manage if the text should be truncated or not.
  const [truncate, setToggleTruncate] = React.useState(true);

// This function toggles the state variable 'truncate', thereby expanding and truncating the text every time the user clicks the div.
  function toggleTruncate() {
    setToggleTruncate(!truncate);
  }

I Stand With Israel
  • 1,971
  • 16
  • 30
3

for CSS only, you can use line-clamp, though it doesn't have the best browser support

Check this codepen for implementation.

  display: block; /* Fallback for non-webkit */
  display: -webkit-box;
  max-width: 400px;
  height: $font-size*$line-height*$lines-to-show; /* Fallback for non-webkit */
  margin: 0 auto;
  font-size: $font-size;
  line-height: $line-height;
  -webkit-line-clamp: $lines-to-show;
  -webkit-box-orient: vertical;
  overflow: hidden;
  text-overflow: ellipsis;
Khodor
  • 996
  • 1
  • 6
  • 13
  • Thanks! this is promising. Although I have to use a react component for some events in it's API. I got the single line with the ellipsis. And i guess it's expected behavior that multiline automatically invokes the scroller so the ellipsis wouldn't work – veggirice Nov 05 '18 at 15:03
  • 1
    This should work normally with react or anything else, since it's a CSS solution. – Khodor Nov 05 '18 at 15:05
  • Yes, true it is straight up css. It doesn't work as well for the react component because it is essentially an tag. where the -webkit-line-clamp doesn't seem to apply. – veggirice Nov 05 '18 at 16:51
  • this is the only thing thats worked so far, but a lot of the properties shouldnt be used in production. nowadays are you aware of any other ways to do it? – oldboy Feb 01 '20 at 22:14
1

The javascript for this could look something like below. You take the value, split it into lines, and if there's more than one line, you wrap the following lines in parentheses.

The React component your using appears to take in an onChange prop, which could use a similar function.

const textAreaElement = document.getElementById('t')

textAreaElement.addEventListener('keyup', () => {
  const value = textAreaElement.value.replace(/[\(\)]/g, '')
  const splitLines = value.split(/(?:\r\n|\r|\n)/)
  
  const newValue = splitLines.length > 1 ?
    `${splitLines[0]}\n(${splitLines.slice(1, splitLines.length).join('\n')})` : splitLines[0]
  
  textAreaElement.value = newValue;
  
});
<textarea id="t"></textarea>
OliverRadini
  • 6,238
  • 1
  • 21
  • 46
0

An easy implementation for multi-line ellipsis will be using antd typography component. You can provide a prop called ellipsis with the value of number of rows after which it should be truncated.

<Paragraph ellipsis={{ rows: 3, expandable: true }}>
  Ant Design, a design language for background applications, is refined by Ant UED Team.
  Ant Design, a design language for background applications, is refined by Ant UED Team.
  Ant Design, a design language for background applications, is refined by Ant UED Team.
  Ant Design, a design language for background applications, is refined by Ant UED Team.
  Ant Design, a design language for background applications, is refined by Ant UED Team.
  Ant Design, a design language for background applications, is refined by Ant UED Team.
</Paragraph>
Rohith Murali
  • 5,551
  • 2
  • 25
  • 26