0

I want to add 'show more' button for overflowed elements then only after clicking on shoe more, I want to show a new line. Here is my code: https://codesandbox.io/s/distracted-microservice-ld267?file=/src/App.js Here is my case we need to do it for an overflowed property like color, Data will be dynamic show for size also if there are more elements, we need to do that. This is the UI for which I want to make, just check It'll help you

  • Please post a [Minimal, Complete, and Reproducible](https://stackoverflow.com/help/minimal-reproducible-example) code example of the relevant code. – Drew Reese Oct 29 '20 at 04:25
  • I think what you are looking for is [here](https://stackoverflow.com/questions/3922739/limit-text-length-to-n-lines-using-css). Please check – Kiran Oct 29 '20 at 05:23
  • A lot of those answers are based on rendering text, which doesn't apply here unfortunately. It'd be amazing if line-clamp applied to arbitrary elements as well – Zachary Haber Oct 29 '20 at 05:54

1 Answers1

0

Here's a solution: the main way this works is by knowing the size that the containing div needs to be, so we can set the height to be the height of one row. Then set overflow: hidden to hide the display of everything past the first row.

This uses CSS variables to allow for more dynamic setting of the sizes of the color squares (based on the buttons that you had showing in the code). Each of the size buttons change the --size CSS variable to change the square sizes.

The height of the containing div is thus height: calc(var(--size) + var(--margin) * 2); which dynamically calculates the height based on the variables so it'll change when the color-blocks change size from the button presses.

The "Show More"/"Show Less" button toggles the showMore state.

const { useState } = React;

const sizeToNumber = {
  standard: "30px",
  medium: "50px",
  small: "15px",
  large: "75px",
  "Extra Large": "100px",
  "Extra Small": "5px"
};

function App() {
  // The current size in pixels - To be used as a CSS variable
  const [size, setSize] = useState(sizeToNumber.standard);
  const onSizeChange = (val) => {
    // Convert from the string text to a pixel value
    setSize(sizeToNumber[val]);
  };

  // State for hiding and showing the extra rows
  const [showMore, setShowMore] = useState(true);

  let data = [
    {
      id: 1,
      name: "Color",
      value: [
        "red",
        "green",
        "yellow",
        "blue",
        "red",
        "green",
        "yellow",
        "blue",
        "red",
        "green",
        "yellow",
        "blue",
        "red",
        "green",
        "yellow",
        "blue",
        "red",
        "green",
        "yellow",
        "blue",
        "red",
        "green",
        "yellow",
        "blue"
      ]
    },
    {
      id: 2,
      name: "Size",
      value: [
        "standard",
        "medium",
        "small",
        "large",
        "Extra Large",
        "Extra Small"
      ]
    }
  ];

  return (
    // Setup --size and --margin CSS variables
    <div style={{ margin: "5px", "--size": size, "--margin": "5px" }}>
      {data.map((d) => {
        const isColor = d.name.toLowerCase().includes("color");
        const hiddenClass = isColor && !showMore ? "hide-rows" : "";
        return (
          <div key={d.id}>
            <div>{d.name}</div>
            <div
              style={{ background: "aqua" }}
              // Set a class if the extra rows should be hidden
              className={"flex " + hiddenClass}
            >
              {d.value.map((val, index) => {
                if (isColor) {
                  return (
                    <div
                      key={index}
                      // This class applies width/height/margin
                      // based on the variables
                      className="color-block"
                      style={{
                        background: val,
                        display: "inline-block"
                      }}
                    ></div>
                  );
                }
                return (
                  <button
                    key={val}
                    // Change the --size variable based on the button pressed!
                    onClick={() => onSizeChange(val)}
                    className="btn btn-primary m-2"
                  >
                    {val}
                  </button>
                );
              })}
            </div>
          </div>
        );
      })}
      <button
        className="btn btn-primary m-2"
        // Toggle showing/hiding everything
        onClick={() => setShowMore(!showMore)}
      >
        {showMore ? "Show Less" : "Show More"}
      </button>
    </div>
  );
}
ReactDOM.render(<App/>,document.getElementById('root'))
.App {
  font-family: sans-serif;
  text-align: center;
}


/* Setup a flex grid to the color-block's parent to make 
   things render consistently */

.flex {
  display: flex;
  flex-wrap: wrap;
}


/* apply margin/width/height variables to the color blocks */

.color-block {
  margin: var(--margin);
  width: var(--size);
  height: var(--size);
}


/* When the extra rows should be hidden, set the height and no overflow
   Height is calculated based on the size + (margin * 2)
   This way things can be dynamically changed, but this will remain possible to use
   since we need to know the height in order to hide things in a reasonable way*/

.hide-rows {
  height: calc(var(--size) + var(--margin) * 2);
  overflow: hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<div id="root" />

Here's the same general principle with the button moved to be inline with the color, and the fun changing of the color swatch sizes removed.

Main difference here is that it uses a flexbox span around the color's div to make it so the "Show More" button appears inline.

const { useState } = React;

function App() {
  // State for hiding and showing the extra rows
  const [showMore, setShowMore] = useState(false);

  let data = [
    {
      id: 1,
      name: "Color",
      value: [
        "red",
        "green",
        "yellow",
        "blue",
        "red",
        "green",
        "yellow",
        "blue",
        "red",
        "green",
        "yellow",
        "blue",
        "red",
        "green",
        "yellow",
        "blue",
        "red",
        "green",
        "yellow",
        "blue",
        "red",
        "green",
        "yellow",
        "blue"
      ]
    },
    {
      id: 2,
      name: "Size",
      value: [
        "standard",
        "medium",
        "small",
        "large",
        "Extra Large",
        "Extra Small"
      ]
    }
  ];

  return (
    <div style={{ margin: "5px" }}>
      {data.map((d) => {
        const isColor = d.name.toLowerCase().includes("color");
        const hiddenClass = isColor && !showMore ? "hide-rows" : "";
        return (
          <div key={d.id}>
            <div>{d.name}</div>
            {/* Extra span around the flex container to make the 
                flex container and the show more button inline */}
            <span style={{ display: "flex" }}>
              <div
                style={{ background: "aqua" }}
                // Set a class if the extra rows should be hidden
                className={"flex " + hiddenClass}
              >
                {d.value.map((val, index) => {
                  if (isColor) {
                    return (
                      <div
                        key={index}
                        // This class applies width/height/margin
                        // based on the variables
                        className="color-block"
                        style={{
                          background: val,
                          display: "inline-block"
                        }}
                      ></div>
                    );
                  }
                  return (
                    <button key={val} className="btn btn-primary m-2">
                      {val}
                    </button>
                  );
                })}
              </div>
              {/* Only display the button on the color section */}
              {/* It is super annoying to try and calculate to determine
                  if there's a need for the show more button.
                  Though doable if you know the size ahead of time*/}
              {isColor && (
                <button
                  className="btn btn-primary"
                  // The button needs to align itself to the top rather than default stretch
                  style={{ alignSelf: "flex-start", marginLeft: "5px" }}
                  // Toggle showing/hiding everything
                  onClick={() => setShowMore(!showMore)}
                >
                  {showMore ? "Show Less" : "Show More"}
                </button>
              )}
            </span>
          </div>
        );
      })}
    </div>
  );
}

ReactDOM.render(<App />,document.getElementById('root'))
.App {
  font-family: sans-serif;
  text-align: center;
}


/* Setup a flex grid to the color-block's parent to make 
   things render consistently */

.flex {
  display: flex;
  flex-wrap: wrap;
  /* Setup --size and --margin CSS variables */
  --size: 30px;
  --margin: 5px;
}


/* apply margin/width/height variables to the color blocks */

.color-block {
  margin: var(--margin);
  width: var(--size);
  height: var(--size);
}


/* When the extra rows should be hidden, set the height and no overflow
   Height is calculated based on the size + (margin * 2)
   This way things can be dynamically changed, but this will remain possible to use
   since we need to know the height in order to hide things in a reasonable way*/

.hide-rows {
  height: calc(var(--size) + var(--margin) * 2);
  overflow: hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<div id="root" />
Zachary Haber
  • 10,376
  • 1
  • 17
  • 31
  • thanks for that. But i think you have misunderstood the question, I've edited my post with an image, you can see and then do that. The thing is like color size is also a property and we also need to do it for size. Just check the image at the end of my post. – Ashutosh Kumar Oct 29 '20 at 05:03