My multi-select custom component did not overflow

I am integrating a multi-select using Material ui, this is what in my .tsx file

import React, { ReactNode } from "react";
import {
  Streamlit,
  StreamlitComponentBase,
  withStreamlitConnection,
} from "streamlit-component-lib";

import FormControl from "@mui/material/FormControl";
import InputLabel from "@mui/material/InputLabel";
import MenuItem from "@mui/material/MenuItem";
import Select, { SelectChangeEvent } from "@mui/material/Select";
import Checkbox from "@mui/material/Checkbox";
import ListItemText from "@mui/material/ListItemText";
import OutlinedInput from "@mui/material/OutlinedInput";

const ITEM_HEIGHT = 48;
const ITEM_PADDING_TOP = 8;
const MenuProps = {
  PaperProps: {
    style: {
      maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP,
      width: 250,
    },
  },
};

interface MultiSelectComponentState {
  selectedItems: string[];
}

class MultiSelectComponent extends StreamlitComponentBase {
  state: MultiSelectComponentState = {
    selectedItems: [],
  };

  handleChange = (event: SelectChangeEvent<typeof this.state.selectedItems>) => {
    const {
      target: { value },
    } = event;
    const names = this.props.args["options"]; // Assuming options are passed from Streamlit

    if (value[value.length - 1] === 'all') {
      const isAllSelected = names.length > 0 && this.state.selectedItems.length === names.length;
      this.setState({
        selectedItems: isAllSelected ? [] : names,
      }, () => {
        Streamlit.setComponentValue(this.state.selectedItems);
      });
    } else {
      this.setState({
        selectedItems: typeof value === "string" ? value.split(",") : value,
      }, () => {
        Streamlit.setComponentValue(this.state.selectedItems);
      });
    }
  };

  render = (): ReactNode => {
    const names = this.props.args["options"]; // Assuming options are passed from Streamlit
    const isAllSelected = names.length > 0 && this.state.selectedItems.length === names.length;

    return (
      <FormControl sx={{mt:5, m: 1, width: 300, height: 250, overflowY: "auto"}}>
        <InputLabel id="multi-select-label">Select Items</InputLabel>
        <Select
          labelId="multi-select-label"
          multiple
          value={this.state.selectedItems}
          onChange={this.handleChange}
          input={<OutlinedInput label="Select Items" />}
          MenuProps={MenuProps}
          renderValue={(selected) => selected.join(", ")}
        >
          <MenuItem value="all">
            <Checkbox checked={isAllSelected} indeterminate={this.state.selectedItems.length > 0 && this.state.selectedItems.length < names.length} />
            <ListItemText primary="Select All" />
          </MenuItem>
          {names.map((name: string) => (
            <MenuItem key={name} value={name}>
              <Checkbox checked={this.state.selectedItems.indexOf(name) > -1} />
              <ListItemText primary={name} />
            </MenuItem>
          ))}
        </Select>
      </FormControl>
    );
  };
}

export default withStreamlitConnection(MultiSelectComponent);

I have 2 issues:

  • It is quite strange that my component did not overflow

  • I cannot capture and return my select to streamlit
    Please help me to fix it. Thank you so much

Maybe it’s not possible. Since the component is inside an iframe, overflow does not work. Using Streamlit.setFrameHeight() can help, with the effect of pushing the entire interface down. Well, at least that’s what I’m seeing in another component, which I’m trying to adjust, without success. It’s st-ant-tree, see how it works at this link.

Maybe this new element helps. Link to documentation.