Knows Not Much
Knows Not Much

Reputation: 31576

React-Select, Multi Select and Text Overflow

I am using React-Select component with multi select. One of the problems I am facing is that if the user select 3 or 4 options the UI looks pretty bad because the text begins to overflow and that causes the component to grow either horizontally and vertically.

I want to have a behavior where the size of the component remains the same and if the user selects more options then it just shows "..." (ellipsis) rather than try to show the newly selected options.

The behavior I want is more inline with this component

http://instructure-react.github.io/react-select-box/

See how it handles multi-select.

I don't want to swap out components now because we have done lots of testing with React-Select.

Can you give me some guide lines on how to achieve this without removing react-select.

Upvotes: 17

Views: 39623

Answers (5)

Shabbir Hossain
Shabbir Hossain

Reputation: 119

You can use something like this.

enter image description here

The demo link is here: https://codesandbox.io/p/sandbox/73zc22?file=%2Fsrc%2FApp.tsx%3A50%2C16

Upvotes: 0

Arnav
Arnav

Reputation: 1

Just do menuPosition="fixed".

Reference: https://github.com/JedWatson/react-select/issues/810#issuecomment-561551914

Upvotes: 0

konuralpt
konuralpt

Reputation: 271

I solved this without losing the Input component like this;

import Select, { components as RSComponents } from "react-select";
   

const ValueContainer = ({ selectProps, children, ...props }) => {
    let [values, input] = children;

    if (Array.isArray(values)) {
      values = selectProps.value.map((x) => x.label).join(', ');
    }

    return (
      <RSComponents.ValueContainer {...props}>
        <div style={{
          maxWidth: "80%",
          whiteSpace: "nowrap",
          textOverflow: "ellipsis",
          overflow: "hidden",
        }}>
          {values}
         </div>
        {input}
      </RSComponents.ValueContainer>
    );
};

const customStyles = useMemo(() => ({
    valueContainer: (provided, state) => ({
        ...provided,
        whiteSpace: "nowrap",
        overflow: "hidden",
        flexWrap: 'nowrap',
    }),
    input: (provided, state) => ({
        ...provided,
        minWidth: '20%'
    }),
}), []);

<Select
    components={{ ValueContainer }}
    isMulti
    styles={customStyles}
    ...
/>

Upvotes: 2

shahar taite
shahar taite

Reputation: 472

i've managed to achieve both the ellipsis effect and leaving the display at one row, here is a working example https://codesandbox.io/s/v638kx67w7 hope this helps

Upvotes: 8

WitVault
WitVault

Reputation: 24140

This is the generated Html for given react-select element

. react-select-box-container {
  position: relative;
  width: 240px;
  display: inline-block;
  background-color: #fff;
  border-radius: 4px;
  text-align: left;
  box-shadow: 0 0 2px rgba(0, 0, 0, .3);
}

.react-select-box {
  padding: 15px 0;
  display: inline-block;
  cursor: pointer;
  border: none;
  width: 100%;
  text-align: left;
  background-color: transparent;
}

.react-select-box:focus {
  outline: 0;
  box-shadow: 0 0 4px #0493D1;
}

.react-select-box:before {
  content: ' ';
  z-index: 1;
  position: absolute;
  height: 20px;
  top: 15px;
  right: 34px;
  border-left: 1px solid #CBD2D7;
}

.react-select-box:after {
  content: ' ';
  position: absolute;
  z-index: 1;
  top: 23px;
  right: 13px;
  border-top: 6px solid #7B8E9B;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
}

.react-select-box-label,
.react-select-box-option {
  line-height: 16px;
  font-size: 12px;
  font-weight: bold;
  color: #7B8E9B;
}

.react-select-box-label {
  padding: 0 40px 0 20px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: #0493D1;
}

.react-select-box-empty .react-select-box-label {
  color: #7B8E9B;
}

.react-select-box-click-outside-layer {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2;
}

.react-select-box-clear {
  position: absolute;
  top: 15px;
  right: 0;
  width: 35px;
  height: 20px;
  background-color: #fff;
  text-indent: -9999em;
  z-index: 3;
  border: none;
}

.react-select-box-clear:before {
  content: '×';
  position: absolute;
  top: 2px;
  left: 10px;
  z-index: 1;
  background-color: #7B8E9B;
  border-radius: 100%;
  font-size: 13px;
  color: #fff;
  line-height: 1;
  width: 15px;
  height: 15px;
  text-indent: 0;
  text-align: center;
}

.react-select-box-clear:hover,
.react-select-box-clear:focus {
  outline: 0;
}

.react-select-box-clear:hover:before,
.react-select-box-clear:focus:before {
  background-color: #0493D1;
}

.react-select-box-hidden {
  display: none
}

.react-select-box-options {
  margin: 2px 0 0;
  position: absolute;
  padding: 10px 0;
  width: 240px;
  top: 100%;
  left: 0;
  z-index: 4;
  background-color: #fff;
  border-radius: 4px;
  box-shadow: 0 0 2px rgba(0, 0, 0, .3);
}

.react-select-box-options-list {
  list-style: none outside;
  margin: 0;
  padding: 0;
}

.react-select-box-option {
  padding: 10px 20px;
  margin: 0;
  cursor: pointer;
  display: block;
  line-height: 1.2;
  text-decoration: none;
}

.react-select-box-option:hover {
  color: #0493D1;
  background-color: #f4f4f4;
}

.react-select-box-option-selected {
  color: #CBD2D7;
}

.react-select-box-multi .react-select-box-option {
  padding-left: 42px;
  position: relative;
}

.react-select-box-multi .react-select-box-option:before {
  content: ' ';
  position: absolute;
  line-height: 1;
  text-align: center;
  left: 20px;
  top: 9px;
  border-radius: 3px;
  height: 12px;
  width: 12px;
  margin-right: 10px;
  border: 1px solid #7B8E9B;
  background: #f9f9f9;
  vertical-align: middle;
}

.react-select-box-multi .react-select-box-option-selected:before {
  content: '✓';
}

.react-select-box-multi .react-select-box-option-selected {
  color: #1F3344;
}

.react-select-box-option:focus,
.react-select-box-option-focused {
  color: #0493D1;
  outline: 0;
  background-color: #DDE2E5;
}

.react-select-box-close {
  color: #0493D1;
  text-transform: uppercase;
  background-color: transparent;
  border: none;
  padding: 5px 0;
  display: block;
  text-align: center;
  width: 100%;
  font-weight: bold;
  cursor: pointer;
  outline: none;
}

.react-select-box-close:hover,
.react-select-box-close:focus {
  text-decoration: underline;
}

.react-select-box-empty .react-select-box-close {
  color: #CBD2D7;
}

.react-select-box-native {
  position: absolute;
  left: -99999em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div class="react-select-box-container react-select-box-multi react-select-box-empty">
  <button id="react-select-box-2" class="react-select-box" tabindex="0" aria-hidden="true">
        <div class="react-select-box-label">
          Favorite Colors
        </div></button>

  <div class="react-select-box-options react-select-box-hidden" aria-hidden="true" tabindex="0">
    <div class="react-select-box-off-screen">
      <a id="react-select-box-2-0" href="#" class="react-select-box-option" tabindex="-1">Red</a>
      <a id="react-select-box-2-1" href="#" class="react-select-box-option" tabindex="-1">Green</a>
      <a id="react-select-box-2-2" href="#" class="react-select-box-option" tabindex="-1">Blue</a>
    </div>
    <button class="react-select-box-close">Close</button>
  </div>

  <div class="react-select-box-native">
    <label for="react-select-box-2-native-select">Favorite Colors</label>
    <select id="react-select-box-2-native-select" multiple="multiple">
            <option value="red">
              Red
            </option>
    
            <option value="green">
              Green
            </option>
    
            <option value="blue">
              Blue
            </option>
          </select>
  </div>
</div>

Upvotes: -2

Related Questions