Skip to content

[select] Support typeahead when closed#48563

Merged
mj12albert merged 4 commits into
mui:masterfrom
mj12albert:select-closed-typeahead
Jun 2, 2026
Merged

[select] Support typeahead when closed#48563
mj12albert merged 4 commits into
mui:masterfrom
mj12albert:select-closed-typeahead

Conversation

@mj12albert
Copy link
Copy Markdown
Member

@mj12albert mj12albert commented May 22, 2026

@mj12albert mj12albert added scope: select Changes related to the select. type: enhancement It’s an improvement, but we can’t make up our mind whether it's a bug fix or a new feature. labels May 22, 2026
@code-infra-dashboard
Copy link
Copy Markdown

code-infra-dashboard Bot commented May 22, 2026

Deploy preview

https://deploy-preview-48563--material-ui.netlify.app/

Bundle size

Bundle Parsed size Gzip size
@mui/material 🔺+1.88KB(+0.36%) 🔺+807B(+0.54%)
@mui/lab 0B(0.00%) 0B(0.00%)
@mui/private-theming 0B(0.00%) 0B(0.00%)
@mui/system 0B(0.00%) 0B(0.00%)
@mui/utils 0B(0.00%) 0B(0.00%)

Details of bundle changes


Check out the code infra dashboard for more information about this PR.

@mj12albert mj12albert force-pushed the select-closed-typeahead branch from a12cc41 to 63fc101 Compare May 22, 2026 11:15
@mj12albert mj12albert force-pushed the select-closed-typeahead branch from 63fc101 to 6c489c3 Compare May 22, 2026 11:45
@mj12albert mj12albert marked this pull request as ready for review May 22, 2026 11:51
Comment on lines +28 to +97
const TYPEAHEAD_RESET_MS = 750;
const SPACE = ' ';
const ARROW_UP = 'ArrowUp';
const ARROW_DOWN = 'ArrowDown';
const ENTER = 'Enter';

function hasOwnValueProp(child) {
return Object.prototype.hasOwnProperty.call(child.props, 'value');
}

function getTextFromReactNode(node) {
if (typeof node === 'string' || typeof node === 'number') {
return String(node);
}

let text = '';

React.Children.forEach(node, (child) => {
if (typeof child === 'string' || typeof child === 'number') {
text += String(child);
} else if (React.isValidElement(child)) {
text += getTextFromReactNode(child.props.children);
}
});

return text;
}

function getMatchingOptionIndex(options, search, startIndex = 0) {
if (options.length === 0) {
return -1;
}

const normalizedStartIndex = ((startIndex % options.length) + options.length) % options.length;

for (let offset = 0; offset < options.length; offset += 1) {
const index = (normalizedStartIndex + offset) % options.length;

if (options[index].label.startsWith(search)) {
return index;
}
}

return -1;
}

function canCycleRepeatedCharacter(options, key) {
return !options.some((option) => option.label[0] === key && option.label[1] === key);
}

function getTypeaheadOptions(childrenArray, value) {
const options = [];
let selectedIndex = -1;

for (let index = 0; index < childrenArray.length; index += 1) {
const child = childrenArray[index];

if (!React.isValidElement(child) || !hasOwnValueProp(child) || child.props.disabled) {
continue;
}

// Closed typeahead cannot exclude CSS-hidden text because no option DOM is mounted.
const label = getTextFromReactNode(child.props.children).trim().toLowerCase();

if (label === '') {
continue;
}

if (selectedIndex === -1 && areEqualValues(value, child.props.value)) {
selectedIndex = options.length;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add all of these in the local utils folder?

@mj12albert mj12albert merged commit 10a49a0 into mui:master Jun 2, 2026
18 checks passed
@mj12albert mj12albert deleted the select-closed-typeahead branch June 2, 2026 12:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

scope: select Changes related to the select. type: enhancement It’s an improvement, but we can’t make up our mind whether it's a bug fix or a new feature.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[select] Support typeahead when closed

2 participants