ant-design icon indicating copy to clipboard operation
ant-design copied to clipboard

Support a valueRender prop for Select

Open anzuj opened this issue 1 year ago • 7 comments

What problem does this feature solve?

More control over the way selected values are shown in multi-selects. There are use cases where we do not want to display tags, for example when we just want to show comma separated values, truncated with an ellipsis. Analog to MUI Select's renderValue

What does the proposed API look like?

Support a valueRender prop allows replacing the content inside .ant-select-selection-overflow div, giving control to how you want to display the array of selected values.

<Select
    className="my-select"
    mode="multiple"
    options={[{
    label: 'Administration category A',
    value: 1,
  }, {
    label: 'Administration category B',
    value: 2,
  }, {
    label: 'Administration category C',
    value: 3,
  }]}
    defaultValue={[1,2]}
    valueRender={values => `${values.map(value => value.label).join(', ')}`}

This would yield the below HTML

<div class="my-select ant-select ant-select-multiple">
    <div class="ant-select-selector">
        <div class="ant-select-selection-wrap">
            <div class="ant-select-selection-overflow">
                  Administration category A, Administration category B
            </div>
        </div>
    </div>
</div>

Which we can style to achieve the overflow ellipsis and a simplified text value display

.my-select.ant-select-multiple .ant-select-selector .ant-select-selection-wrap .ant-select-selection-overflow {
    white-space: nowrap;
    text-overflow: ellipsis;
}

anzuj avatar Apr 23 '25 08:04 anzuj

Thank you for your feature request regarding the valueRender prop for the Select component in Ant Design. This feature would indeed provide more flexibility in displaying selected values in multi-select scenarios, allowing for custom rendering such as comma-separated values with ellipsis.

Your proposal to introduce a valueRender prop is noted, and it will be considered by the team. This prop would allow developers to customize the display of selected values, enhancing the user interface according to specific needs.

If you have any further questions or additional details to provide, feel free to comment here.

🪧 Tips For further assistance, please describe your question in the comments and @petercat-assistant to start a conversation with me.

petercat-assistant[bot] avatar Apr 23 '25 08:04 petercat-assistant[bot]

Yes, I think your need is very meaningful, and I also took a look at the <Select /> component documentation of antd. The current tagRender and labelRender both cannot achieve combined customization.

The <Select /> should refer to the <Cascader /> and provide a displayRender prop to support this behavior.

Wxh16144 avatar Apr 28 '25 01:04 Wxh16144

label is all you need.

afc163 avatar Apr 28 '25 02:04 afc163

There is an internal method that can directly modify the selector trigger, allowing for customized display content.

import React from "react";
import { Input, Select } from "antd";

const MSelect = Select as any;

const options = [
  {
    label: "A",
    value: "a",
  },
  {
    label: "B",
    value: "b",
  },
  {
    label: "C",
    value: "c",
  },
];

const App = () => {
  const [value, setValue] = React.useState<string[]>();

  const displayValue = options
    .filter((item) => value?.includes(item.value))
    .map((item) => item.label)
    .join(", ");

  return (
    <>
      <MSelect
        getRawInputElement={() => (
          <Input
            readOnly
            variant="filled"
            value={displayValue}
            style={{
              width: "auto",
              minWidth: 200,
            }}
          />
        )}
        value={value}
        onChange={setValue}
        mode="multiple"
        options={options}
      >
        <div style={{ width: 120, height: 120, background: "red" }}></div>
      </MSelect>
    </>
  );
};

export default App;

https://github.com/user-attachments/assets/8933c8f3-e6f3-4141-a3b2-fdc1b7dc48ab

Wxh16144 avatar Apr 28 '25 10:04 Wxh16144

https://ant.design/components/select#select-demo-option-render Did you mean this?

MadCcc avatar Apr 30 '25 08:04 MadCcc

@Wxh16144 Thank you for thinking along but I think using getRawInputElement to overwrite the underlying Input adds unnecessary complexity, extra state management and loses a bulk of the Select out-of-the-box functionality. In practice I would have to carefully reassign all validation props, mimic the dropdown toggle, implement the clear icon + functionality etc.

There is an internal method that can directly modify the selector trigger, allowing for customized display content.

@afc163 Can you clarify your comment please? How can the label achieve a multiple Select value being displayed as "Administration A, Administr..." without the tags?

anzuj avatar Apr 30 '25 10:04 anzuj

For the time being this is a "hacky" workaround I've come up with:

<Select
    className="my-select"
    mode="multiple"
    options={[{
       label: 'Administration category A',
       value: 1,
     }, {
       label: 'Administration category B',
       value: 2,
    }, {
      label: 'Administration category C',
      value: 3,
    }]}
    maxTagCount={0}
    maxTagPlaceholder={(omittedValues)=> {
       const valueString = omittedValues.map(omittedValue => omittedValue.label).join(', ')
       return <Tooltip title={valueString}>{valueString}</Tooltip>
    }}

   />

Coupled with scss to overwrite Ant Design's attempt to leave space for tags + search

.my-select.ant-select-multiple {
    height: 32px;
    max-height:32px;
    .ant-select-selector {
        &:after{
            margin: 0;
            line-height:21px;
        }
        
        .ant-select-selection-wrap {
            align-self:center;
            &:after{
                margin-block:0;
                margin: 0;
                line-height:21px;
            }
            .ant-select-selection-overflow {
                white-space: nowrap;
                text-overflow: ellipsis;
            }
    
            .ant-select-selection-overflow-item-suffix {
              position: absolute;
              right: 0;
              margin-block: 0;
            }
    
            .ant-select-selection-item {
                background: none;
            }
        }
    }
}

I realise Ant Design is a design system, but flexibility in allowing users to divert from the default tag rendering would be very welcome and. In many real-world scenarios even necessary. Below is an example from the dashboard I'm working on:

Image

Since the first selected value was just 2 characters too long for the Select to fully show as a tag, we see no value information anymore whatsoever. To show the shorter labels when possible also requires maxTagCount="responsive" which as we know has a performance cost. My use case would be solved with the valueRender prop without having to hack scss and I dare to guess I'm not alone as most other UI systems (MUI, Vuetify etc) all support this functionality with no fuss.

anzuj avatar Apr 30 '25 10:04 anzuj