Skip to content

[material-ui][Select] Fix autoWidth sizing with InputLabel #45862

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/translations/api-docs/select/select.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"componentDescription": "",
"propDescriptions": {
"autoWidth": {
"description": "If <code>true</code>, the width of the popover will automatically be set according to the items inside the menu, otherwise it will be at least the width of the select input."
"description": "If <code>true</code>, the width of the popover will automatically be set according to the items inside the menu, otherwise it will be at least the width of the select input or the <code>InputLabel</code> associated with <code>labelId</code>."
},
"children": {
"description": "The option elements to populate the select with. Can be some <code>MenuItem</code> when <code>native</code> is false and <code>option</code> when <code>native</code> is true.<br>⚠️The <code>MenuItem</code> elements <strong>must</strong> be direct descendants when <code>native</code> is false."
Expand Down
2 changes: 1 addition & 1 deletion packages/mui-material/src/Select/Select.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export interface BaseSelectProps<Value = unknown>
extends StandardProps<InputProps, 'value' | 'onChange' | 'placeholder'> {
/**
* If `true`, the width of the popover will automatically be set according to the items inside the
* menu, otherwise it will be at least the width of the select input.
* menu, otherwise it will be at least the width of the select input or the `InputLabel` associated with `labelId`.
* @default false
*/
autoWidth?: boolean;
Expand Down
2 changes: 1 addition & 1 deletion packages/mui-material/src/Select/Select.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ Select.propTypes /* remove-proptypes */ = {
// └─────────────────────────────────────────────────────────────────────┘
/**
* If `true`, the width of the popover will automatically be set according to the items inside the
* menu, otherwise it will be at least the width of the select input.
* menu, otherwise it will be at least the width of the select input or the `InputLabel` associated with `labelId`.
* @default false
*/
autoWidth: PropTypes.bool,
Expand Down
34 changes: 25 additions & 9 deletions packages/mui-material/src/Select/Select.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,17 +225,33 @@ describe('<Select />', () => {
expect(handleClose.callCount).to.equal(1);
});

it('should focus select when its label is clicked', () => {
const { getByRole, getByTestId } = render(
<React.Fragment>
<InputLabel id="my$label" data-testid="label" />
<Select value="" labelId="my$label" />
</React.Fragment>,
);
describe('when select is used with <InputLabel>', () => {
it('should focus select when its label is clicked', () => {
const { getByRole, getByTestId } = render(
<React.Fragment>
<InputLabel id="my$label" data-testid="label" />
<Select value="" labelId="my$label" />
</React.Fragment>,
);

fireEvent.click(getByTestId('label'));
fireEvent.click(getByTestId('label'));

expect(getByRole('combobox')).toHaveFocus();
expect(getByRole('combobox')).toHaveFocus();
});

it('should use a given labelIds text content when autoWidth is true', () => {
const labelText = 'Test Label Text';
const { getByTestId } = render(
<React.Fragment>
<InputLabel id="auto-width-label">{labelText}</InputLabel>
<Select labelId="auto-width-label" data-testid="select" autoWidth value=""/>
</React.Fragment>,
);

const selectElement = getByTestId('select')

expect(selectElement.textContent).to.equal(`${labelText}\u200B`);
});
});

it('should focus list if no selection', () => {
Expand Down
26 changes: 21 additions & 5 deletions packages/mui-material/src/Select/SelectInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ const SelectInput = React.forwardRef(function SelectInput(props, ref) {
const { current: isOpenControlled } = React.useRef(openProp != null);
const [menuMinWidthState, setMenuMinWidthState] = React.useState();
const handleRef = useForkRef(ref, inputRefProp);
const [labelText, setLabelText] = React.useState('\u200B');

const handleDisplayRef = React.useCallback((node) => {
displayRef.current = node;
Expand Down Expand Up @@ -210,6 +211,20 @@ const SelectInput = React.forwardRef(function SelectInput(props, ref) {
return undefined;
}, [labelId]);

React.useEffect(() => {
if (!autoWidth || !labelId || !displayRef.current) {
return;
}
const label = ownerDocument(displayRef.current).getElementById(labelId);
if (label && !displayEmpty) {
// The label returns it's text with a zero width space, we should remove this as it could effect string
const cleanLabelText = label.textContent.replace(/\u200B/g, '');
setLabelText(cleanLabelText);
} else {
setLabelText('\u200B');
}
}, [autoWidth, labelId, displayEmpty]);

const update = (open, event) => {
if (open) {
if (onOpen) {
Expand Down Expand Up @@ -516,11 +531,12 @@ const SelectInput = React.forwardRef(function SelectInput(props, ref) {
// The id is required for proper a11y
id={buttonId}
>
{/* So the vertical align positioning algorithm kicks in. */}
{isEmpty(display) ? (
// notranslate needed while Google Translate will not fix zero-width space issue
<span className="notranslate" aria-hidden>
&#8203;
// notranslate class Prevents Google Translate issues with zero-width spaces
// Enables dynamic sizing with <InputLabel> when autoWidth=true
// Maintains alignment with '\u200B' when no label/autoWidth
<span className="notranslate" style={{ color: 'transparent' }} aria-hidden>
{labelText}
</span>
) : (
display
Expand Down Expand Up @@ -596,7 +612,7 @@ SelectInput.propTypes = {
autoFocus: PropTypes.bool,
/**
* If `true`, the width of the popover will automatically be set according to the items inside the
* menu, otherwise it will be at least the width of the select input.
* menu, otherwise it will be at least the width of the select input or the 'InputLabel' associated with 'labelId'.
*/
autoWidth: PropTypes.bool,
/**
Expand Down
Loading