Skip to content
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

[ButtonGroup] Fix rendering with conditional elements #38989

19 changes: 11 additions & 8 deletions packages/mui-material/src/ButtonGroup/ButtonGroup.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
import clsx from 'clsx';
import { unstable_composeClasses as composeClasses } from '@mui/base/composeClasses';
import { alpha } from '@mui/system';
import { getValidReactChildren } from '@mui/utils';
import capitalize from '../utils/capitalize';
import styled from '../styles/styled';
import useThemeProps from '../styles/useThemeProps';
Expand Down Expand Up @@ -256,9 +257,12 @@ const ButtonGroup = React.forwardRef(function ButtonGroup(inProps, ref) {
],
);

const getButtonPositionClassName = (index, childrenParam) => {
const validChildren = getValidReactChildren(children);
const childrenCount = validChildren.length;

const getButtonPositionClassName = (index) => {
const isFirstButton = index === 0;
const isLastButton = index === React.Children.count(childrenParam) - 1;
const isLastButton = index === childrenCount - 1;

if (isFirstButton && isLastButton) {
return '';
Expand All @@ -282,13 +286,12 @@ const ButtonGroup = React.forwardRef(function ButtonGroup(inProps, ref) {
{...other}
>
<ButtonGroupContext.Provider value={context}>
{React.Children.map(children, (child, index) => {
if (!React.isValidElement(child)) {
return child;
}

{validChildren.map((child, index) => {
return (
<ButtonGroupButtonContext.Provider value={getButtonPositionClassName(index, children)}>
<ButtonGroupButtonContext.Provider
key={index}
value={getButtonPositionClassName(index)}
>
{child}
</ButtonGroupButtonContext.Provider>
);
Expand Down
13 changes: 13 additions & 0 deletions packages/mui-utils/src/getValidReactChildren.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import * as React from 'react';

/**
* Gets only the valid children of a component,
* and ignores any nullish or falsy child.
*
* @param children the children
*/
export default function getValidReactChildren(children: React.ReactNode) {
return React.Children.toArray(children).filter((child) =>
React.isValidElement(child),
) as React.ReactElement[];
}
1 change: 1 addition & 0 deletions packages/mui-utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export {
getNormalizedScrollLeft as unstable_getNormalizedScrollLeft,
} from './scrollLeft';
export { default as usePreviousProps } from './usePreviousProps';
export { default as getValidReactChildren } from './getValidReactChildren';
export { default as visuallyHidden } from './visuallyHidden';
export { default as integerPropType } from './integerPropType';
export { default as internal_resolveProps } from './resolveProps';
Expand Down
9 changes: 9 additions & 0 deletions test/regressions/fixtures/ButtonGroup/DifferentChildren.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import Stack from '@mui/material/Stack';
import Tooltip from '@mui/material/Tooltip';

export default function DifferentChildren() {
const falsyCondition = 1 === 2;

return (
<Stack spacing={2}>
{/* It has one button with href which is rendered as anchor tag */}
Expand Down Expand Up @@ -35,6 +37,13 @@ export default function DifferentChildren() {
<ButtonGroup>
<Button>Single Button</Button>
</ButtonGroup>

{/* Conditional elements */}
<ButtonGroup>
<Button>One</Button>
<Button>Two</Button>
{falsyCondition ? <Button>Three</Button> : undefined}
</ButtonGroup>
</Stack>
);
}