11

For a reactjs app, I use Material-ui (https://material-ui.com/) for the design. And I need to write text in card that match exactly 2 lines.

What I've already done works when text can be contained in 2 or 1 lines, but for longer text, the cut becomes before word and it is not ellipsis.

enter image description here

Here what I've done

   <Box
        fontSize="h5.fontSize"
        component="div"
        overflow="hidden"
        textOverflow="ellipsis"
        height={70}
      >
        {title}
      </Box>

The result is good on the first card, for on the second one, the last word 'Floooooo' is displayed in the hidden part (the third line) but not in the second line with ellipsis. I've tried to add whiteSpace="nowrap" but the text is only 1 line height (fig 2) enter image description here

Can you help me please?

Turvy
  • 882
  • 1
  • 8
  • 23

4 Answers4

20
<Typography
  sx={{
    overflow: "hidden",
    textOverflow: "ellipsis",
    display: "-webkit-box",
    WebkitLineClamp: "2",
    WebkitBoxOrient: "vertical",
  }}>
  overflowing text...
</Typography>

Note

'sx' is a property that works in newer version of MUI

Chukwuemeka Maduekwe
  • 6,687
  • 5
  • 44
  • 67
7

You can use CSS rule -webkit-line-clamp: 2 in conjuction with word-break: break-all

const useStyles = makeStyles({
  root: {
    maxWidth: 300,
  },
  media: {
    height: 100,
  },
  customBox: {
    display: "-webkit-box",
    boxOrient: "vertical",
    lineClamp: 2,
    wordBreak: "break-all",
    overflow: "hidden"
  }
});

function App() {

  const classes = useStyles();
  const title = "pos2 test long Flooooooooooooooooooooooooooooooooooo";

  return (
    <Card className={classes.root}>
      <CardMedia
        className={classes.media}
        image="https://via.placeholder.com/300x100"
      />
      <CardContent>
        <Box
          fontSize="h5.fontSize"
          component="div"
          classes={{root: classes.customBox}}
        >
          {title}
        </Box>
      </CardContent>
    </Card>
  );
}

ReactDOM.render(<App/>, document.getElementById("root"));
<body>
  <div id="root"></div>

  <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
  <script src="https://unpkg.com/@material-ui/core@latest/umd/material-ui.development.js"></script>

  <script type="text/babel">
    const { Box, Card, CardContent, CardMedia, makeStyles } = MaterialUI;
  </script>
</body>
95faf8e76605e973
  • 13,643
  • 3
  • 24
  • 51
  • It's quite good, I was impired by https://stackoverflow.com/questions/11989546/wrap-a-text-within-only-two-lines-inside-div for finding my solution. The problem with yours is that all words are cut. In my case, I can have the word "long" cut in lines – Turvy Oct 12 '20 at 10:50
  • It's working!!!! Thanks – gurkan Nov 27 '21 at 09:23
2

Try like this:

<CardContent style={{width: "auto"}}>
          <Box
            fontSize="h5.fontSize"
            component="div" 
            overflow="hidden"            
            whiteSpace="pre-line"
            textOverflow="ellipsis"
            height={70}          
          >
            {title}
          </Box>
</CardContent>
Rohitha
  • 776
  • 3
  • 8
1

For those who wants to override noWrap property on Typography component, you can do this in your createTheme() as follows:

const theme = createTheme({
    components: {
        MuiTypography: {
            styleOverrides: {
                noWrap: {
                    whiteSpace: "initial",
                    overflow: "hidden",
                    textOverflow: "ellipsis",
                    display: "-webkit-box",
                    WebkitLineClamp: "2",
                    WebkitBoxOrient: "vertical",
                }
            }
        }
    },
    [...] //your other overrides
});

Then just use in your code as usually:

<Typography noWrap>[Your overflowing text]</Typography>

More info about this here: https://mui.com/material-ui/customization/theme-components/#overrides-based-on-props


If you want the number of lines to be customizable I came to this pretty ugly solution:

const theme = createTheme({
    components: {
        MuiTypography: {
            styleOverrides: {
                noWrap(styles) {
                    return {
                        whiteSpace: "initial",
                        overflow: "hidden",
                        textOverflow: "ellipsis",
                        display: "-webkit-box",
                        WebkitLineClamp: String(styles.ownerState['data-lines'] || '2'),
                        WebkitBoxOrient: "vertical",
                    }
                }
            }
        }
    },
    [...] //your other overrides
});

Then:

<Typography noWrap data-lines="3">[Your overflowing text]</Typography>

edson alves
  • 200
  • 1
  • 12