Barun Patro
Barun Patro

Reputation: 860

Material UI dropdown showing inappropriate height

I am trying to use Material UI dropdown in my website, using react-select library. The problem is, when I'm using an option longer than the dropdown width, it compromises the UI.

Can anyone please help me out here.

Here is my react code:

import React, { useState } from "react";
import "./styles.css";
import SelectDropdown from "./EditableDropdown";

export default function App() {
  const [description, setDesc] = useState("");

  const options = [
    {
      label: "a11 b33 c88 o99 t66 j44 z99",
      value: "a11 b33 c88 o99 t66 j44 z99"
    },
    {
      label: "Switches",
      value: "Switches"
    }
  ];

  return (
    <div style={{ width: "25%" }}>
      <SelectDropdown
        label="Description"
        value={description}
        onChange={setDesc}
        options={options}
      />
    </div>
  );
}

Here is the code for the Editable component

import React from "react";
import {
  MuiThemeProvider,
  createMuiTheme,
  MenuItem,
  Paper,
  withStyles,
  TextField
} from "@material-ui/core";
import Select from "react-select";

const styles = {
  input: {
    padding: 0,
    marginSides: "8px",
    minHeight: "inherit",
    lineHeight: "22px",
    fontWeight: 200
  },
  valueContainer: {
    alignItems: "center",
    fontFamily: "Helvetica Neue,Arial,Helvetica,sans-serif",
    fontWeight: 400,
    fontSize: "14px !important"
  }
};

function inputComponent({ inputRef, ...props }) {
  return <div ref={inputRef} {...props} />;
}

function Control(props) {
  return (
    <TextField
      fullWidth
      InputProps={{
        inputComponent,
        inputProps: {
          className: props.selectProps.classes.input,
          children: props.children,
          ...props.innerProps
        }
      }}
      {...props.selectProps.textFieldProps}
    />
  );
}

function Option(props) {
  return (
    <MenuItem
      buttonRef={props.innerRef}
      selected={props.isFocused}
      component="div"
      style={{
        fontWeight: props.isSelected ? 500 : 400,
        backgroundColor: props.isSelected
          ? "rgba(59,234,31,0.2)"
          : props.isFocused
          ? "#F0F0F0"
          : null,
        fontFamily: "Helvetica Neue,Arial,Helvetica,sans-serif",
        height: "34px",
        color: "#343434"
      }}
      {...props.innerProps}
    >
      {props.children}
    </MenuItem>
  );
}

function SingleValue(props) {
  return (
    <div
      className={props.selectProps.classes.singleValue}
      {...props.innerProps}
    >
      {typeof props.children !== "object" ? props.children : ""}
    </div>
  );
}

function ValueContainer(props) {
  let valueContainerClass = props.selectProps.classes.valueContainer;
  return (
    <div className={valueContainerClass} ref={props.inputRef}>
      {props.children}
    </div>
  );
}

function Menu(props) {
  return (
    <Paper square {...props.innerProps}>
      {props.children}
    </Paper>
  );
}

const dropDownStyle = {
  overrides: {
    MuiOutlinedInput: {
      root: {
        padding: "12px 12px 12px 16px !important"
      }
    },
    MuiInputBase: {
      root: {
        cursor: "pointer"
      }
    }
  }
};

class SelectDropdown extends React.Component {
  state = {
    focused: false
  };

  handleTextFieldChange = ({ target: { value } }) => {
    this.props.onChange({
      label: value,
      value
    });
  };

  components = {
    Control,
    Menu,
    Option,
    SingleValue,
    ValueContainer,
    IndicatorSeparator: () => null,
    DropdownIndicator: () => null
  };

  render() {
    const { classes, options, onChange, value } = this.props;

    const selectStyles = {
      clearIndicator: () => ({
        display: "none"
      }),
      noOptionsMessage: () => ({
        display: "none"
      })
    };
    return (
      <MuiThemeProvider theme={createMuiTheme(dropDownStyle)}>
        <Select
          styles={selectStyles}
          isClearable={true}
          classes={classes}
          onChange={onChange}
          backspaceRemovesValue={true}
          textFieldProps={{
            label: this.props.label,
            variant: "outlined",
            InputLabelProps: value ? { shrink: true } : {},
            onChange: this.handleTextFieldChange
          }}
          value={value}
          components={this.components}
          isSearchable={true}
          placeholder=""
          options={options}
        />
      </MuiThemeProvider>
    );
  }
}

export default withStyles(styles, { withTheme: true })(SelectDropdown);

and here is a link to same code in a sandbox: https://codesandbox.io/s/editable-dropdown-ckf1r

Upvotes: 1

Views: 1296

Answers (1)

mw509
mw509

Reputation: 2093

I believe you are better off using material-ui directly instead of EditableDropdown. Since the latter has limitations.

Also you are better off using a newer version of Material-UI.

Here is a code in Material-UI (V4.9.5) that works just as you want it. If you want to add styling to it, you can always use CSS to

import React from 'react';
import TextField from '@material-ui/core/TextField';
import Autocomplete, { createFilterOptions } from '@material-ui/lab/Autocomplete';

const filter = createFilterOptions();

export default function FreeSoloCreateOption() {
  const [value, setValue] = React.useState(null);

  return (
    <Autocomplete
      value={value}
      onChange={(event, newValue) => {
        if (newValue && newValue.inputValue) {
          setValue({
            title: newValue.inputValue,
          });

          return;
        }

        setValue(newValue);
      }}
      filterOptions={(options, params) => {
        const filtered = filter(options, params);

        if (params.inputValue !== '') {
          filtered.push({
            inputValue: params.inputValue,
            title: `Add "${params.inputValue}"`,
          });
        }

        return filtered;
      }}
      id="free-solo-with-text-demo"
      options={top100Films}
      getOptionLabel={option => {
        // e.g value selected with enter, right from the input
        if (typeof option === 'string') {
          return option;
        }
        if (option.inputValue) {
          return option.inputValue;
        }
        return option.title;
      }}
      renderOption={option => option.title}
      style={{ width: 300 }}
      freeSolo
      renderInput={params => (
        <TextField {...params} label="Free solo with text demo" variant="outlined" />
      )}
    />
  );
}

// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top
const top100Films = [
  { title: 'Raiders of the Lost Ark', year: 1981 },
  { title: 'Rear Window', year: 1954 },
  { title: 'The Pianist', year: 2002 },
  { title: 'The Departed', year: 2006 },
  { title: 'Terminator 2: Judgment Day', year: 1991 },
  { title: 'Back to the Future', year: 1985 },
  { title: 'Whiplash', year: 2014 },
  { title: 'Gladiator', year: 2000 },
  { title: 'Memento', year: 2000 },
  { title: 'The Prestige', year: 2006 },
  { title: 'The Lion King', year: 1994 },
  { title: 'Apocalypse Now', year: 1979 },
  { title: 'Alien', year: 1979 },
  { title: 'Sunset Boulevard', year: 1950 },
  {
    title: 'Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb',
    year: 1964,
  },
];

Reference: https://material-ui.com/components/autocomplete/ Link to code: https://codesandbox.io/s/gbljf

Let me know if this helps.

Upvotes: 1

Related Questions