Unstyled button
Buttons allow users to take actions and make choices with a single tap.
Basic button
import ButtonUnstyled from '@mui/base/ButtonUnstyled';
<ButtonUnstyled>Button</ButtonUnstyled>;
import * as React from 'react';
import ButtonUnstyled, { buttonUnstyledClasses } from '@mui/base/ButtonUnstyled';
import { styled } from '@mui/system';
import Stack from '@mui/material/Stack';
const blue = {
500: '#007FFF',
600: '#0072E5',
700: '#0059B2',
};
const CustomButton = styled(ButtonUnstyled)`
font-family: IBM Plex Sans, sans-serif;
font-weight: bold;
font-size: 0.875rem;
background-color: ${blue[500]};
padding: 12px 24px;
border-radius: 8px;
color: white;
transition: all 150ms ease;
cursor: pointer;
border: none;
&:hover {
background-color: ${blue[600]};
}
&.${buttonUnstyledClasses.active} {
background-color: ${blue[700]};
}
&.${buttonUnstyledClasses.focusVisible} {
box-shadow: 0 4px 20px 0 rgba(61, 71, 82, 0.1), 0 0 0 5px rgba(0, 127, 255, 0.5);
outline: none;
}
&.${buttonUnstyledClasses.disabled} {
opacity: 0.5;
cursor: not-allowed;
}
`;
export default function UnstyledButtonsSimple() {
return (
<Stack spacing={2} direction="row">
<CustomButton>Button</CustomButton>
<CustomButton disabled>Disabled</CustomButton>
</Stack>
);
}
Customizing the root element
By default, the ButtonUnstyled
component renders a native button
HTML element.
You can override this by setting the component
or components.Root
prop.
If you provide a non-interactive element such as a <span>
, the ButtonUnstyled
component will automatically add the necessary accessibility attributes.
Compare the attributes on the <span>
in this demo with the ButtonUnstyled
from the previous demo:
<CustomButton component="span">Button</CustomButton>
<CustomButton component="span" disabled>
Disabled
</CustomButton>
Complex customization
ButtonUnstyled
accepts a wide range of custom elements beyond HTML elements.
You can even use SVGs, as the following demo illustrates:
Focus on disabled buttons
Similarly to the native HTML <button>
element, the ButtonUnstyled
component can't receive focus when it's disabled.
This may reduce its accessibility, as screen readers won't be able to announce the existence and state of the button.
The focusableWhenDisabled
prop lets you change this behavior.
When this prop is set, the underlying button does not set the disabled
prop.
Instead, aria-disabled
is used, which makes the button focusable.
This should be used whenever the disabled button needs to be read by screen readers.
MUI Base uses this prop internally in menu items, making it possible to use the keyboard to navigate to disabled items (in compliance with ARIA guidelines).
<CustomButton disabled>focusableWhenDisabled = false</CustomButton>
<CustomButton disabled focusableWhenDisabled>
focusableWhenDisabled = true
</CustomButton>
The focusWhenDisabled
prop works the same when the root slot is customized, except that the aria-disabled
attribute is used no regardless of the prop's state.
The ability to receive focus is controlled internally by the tabindex
attribute.
<CustomButton component="span" disabled>
focusableWhenDisabled = false
</CustomButton>
<CustomButton component="span" disabled focusableWhenDisabled>
focusableWhenDisabled = true
</CustomButton>
The useButton hook
import { useButton } from '@mui/base/ButtonUnstyled';
The useButton
hook lets you use the functionality of ButtonUnstyled
in other components.
It returns props to be placed on a custom button element, along with fields representing the internal state of the button.
The useButton
hook requires the ref
of the element it's used on.
Additionally, you need to provide the component
prop (unless you intend to use the native HTML <button>
).
import * as React from 'react';
import clsx from 'clsx';
import { ButtonUnstyledProps, useButton } from '@mui/base/ButtonUnstyled';
import { styled } from '@mui/system';
import Stack from '@mui/material/Stack';
const blue = {
500: '#007FFF',
600: '#0072E5',
700: '#0059B2',
};
const CustomButtonRoot = styled('button')`
font-family: IBM Plex Sans, sans-serif;
font-weight: bold;
font-size: 0.875rem;
background-color: ${blue[500]};
padding: 12px 24px;
border-radius: 8px;
color: white;
transition: all 150ms ease;
cursor: pointer;
border: none;
&:hover {
background-color: ${blue[600]};
}
&.active {
background-color: ${blue[700]};
}
&.focusVisible {
box-shadow: 0 4px 20px 0 rgba(61, 71, 82, 0.1), 0 0 0 5px rgba(0, 127, 255, 0.5);
outline: none;
}
&.disabled {
opacity: 0.5;
cursor: not-allowed;
}
`;
const CustomButton = React.forwardRef(function CustomButton(
props: ButtonUnstyledProps,
ref: React.ForwardedRef<any>,
) {
const { children } = props;
const { active, disabled, focusVisible, getRootProps } = useButton({
...props,
ref,
});
const classes = {
active,
disabled,
focusVisible,
};
return (
<CustomButtonRoot {...getRootProps()} className={clsx(classes)}>
{children}
</CustomButtonRoot>
);
});
export default function UseButton() {
return (
<Stack spacing={2} direction="row">
<CustomButton onClick={() => console.log('click!')}>Button</CustomButton>
<CustomButton disabled>Disabled</CustomButton>
</Stack>
);
}