UNPKG

@mui/material

Version:

Material UI is an open-source React component library that implements Google's Material Design. It's comprehensive and can be used in production out of the box.

777 lines (649 loc) • 26.1 kB
--- productId: material-ui title: Toggle Button React component components: ToggleButton, ToggleButtonGroup githubLabel: 'scope: toggle button' materialDesign: https://m2.material.io/components/buttons#toggle-button githubSource: packages/mui-material/src/ToggleButton --- # Toggle Button A Toggle Button can be used to group related options. To emphasize groups of related Toggle buttons, a group should share a common container. The `ToggleButtonGroup` controls the selected state of its child buttons when given its own `value` prop. ## Exclusive selection With exclusive selection, selecting one option deselects any other. In this example, text justification toggle buttons present options for left, center, right, and fully justified text (disabled), with only one item available for selection at a time. **Note**: Exclusive selection does not enforce that a button must be active. For that effect see [enforce value set](#enforce-value-set). ```tsx import * as React from 'react'; import FormatAlignLeftIcon from '@mui/icons-material/FormatAlignLeft'; import FormatAlignCenterIcon from '@mui/icons-material/FormatAlignCenter'; import FormatAlignRightIcon from '@mui/icons-material/FormatAlignRight'; import FormatAlignJustifyIcon from '@mui/icons-material/FormatAlignJustify'; import ToggleButton from '@mui/material/ToggleButton'; import ToggleButtonGroup from '@mui/material/ToggleButtonGroup'; export default function ToggleButtons() { const [alignment, setAlignment] = React.useState<string | null>('left'); const handleAlignment = ( event: React.MouseEvent<HTMLElement>, newAlignment: string | null, ) => { setAlignment(newAlignment); }; return ( <ToggleButtonGroup value={alignment} exclusive onChange={handleAlignment} aria-label="text alignment" > <ToggleButton value="left" aria-label="left aligned"> <FormatAlignLeftIcon /> </ToggleButton> <ToggleButton value="center" aria-label="centered"> <FormatAlignCenterIcon /> </ToggleButton> <ToggleButton value="right" aria-label="right aligned"> <FormatAlignRightIcon /> </ToggleButton> <ToggleButton value="justify" aria-label="justified" disabled> <FormatAlignJustifyIcon /> </ToggleButton> </ToggleButtonGroup> ); } ``` ## Multiple selection Multiple selection allows for logically-grouped options, like bold, italic, and underline, to have multiple options selected. ```tsx import * as React from 'react'; import FormatBoldIcon from '@mui/icons-material/FormatBold'; import FormatItalicIcon from '@mui/icons-material/FormatItalic'; import FormatUnderlinedIcon from '@mui/icons-material/FormatUnderlined'; import FormatColorFillIcon from '@mui/icons-material/FormatColorFill'; import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown'; import ToggleButton from '@mui/material/ToggleButton'; import ToggleButtonGroup from '@mui/material/ToggleButtonGroup'; export default function ToggleButtonsMultiple() { const [formats, setFormats] = React.useState(() => ['bold', 'italic']); const handleFormat = ( event: React.MouseEvent<HTMLElement>, newFormats: string[], ) => { setFormats(newFormats); }; return ( <ToggleButtonGroup value={formats} onChange={handleFormat} aria-label="text formatting" > <ToggleButton value="bold" aria-label="bold"> <FormatBoldIcon /> </ToggleButton> <ToggleButton value="italic" aria-label="italic"> <FormatItalicIcon /> </ToggleButton> <ToggleButton value="underlined" aria-label="underlined"> <FormatUnderlinedIcon /> </ToggleButton> <ToggleButton value="color" aria-label="color" disabled> <FormatColorFillIcon /> <ArrowDropDownIcon /> </ToggleButton> </ToggleButtonGroup> ); } ``` ## Size For larger or smaller buttons, use the `size` prop. ```tsx import * as React from 'react'; import FormatAlignLeftIcon from '@mui/icons-material/FormatAlignLeft'; import FormatAlignCenterIcon from '@mui/icons-material/FormatAlignCenter'; import FormatAlignRightIcon from '@mui/icons-material/FormatAlignRight'; import FormatAlignJustifyIcon from '@mui/icons-material/FormatAlignJustify'; import Stack from '@mui/material/Stack'; import ToggleButton from '@mui/material/ToggleButton'; import ToggleButtonGroup from '@mui/material/ToggleButtonGroup'; export default function ToggleButtonSizes() { const [alignment, setAlignment] = React.useState('left'); const handleChange = ( event: React.MouseEvent<HTMLElement>, newAlignment: string, ) => { setAlignment(newAlignment); }; const children = [ <ToggleButton value="left" key="left"> <FormatAlignLeftIcon /> </ToggleButton>, <ToggleButton value="center" key="center"> <FormatAlignCenterIcon /> </ToggleButton>, <ToggleButton value="right" key="right"> <FormatAlignRightIcon /> </ToggleButton>, <ToggleButton value="justify" key="justify"> <FormatAlignJustifyIcon /> </ToggleButton>, ]; const control = { value: alignment, onChange: handleChange, exclusive: true, }; return ( <Stack spacing={2} sx={{ alignItems: 'center' }}> <ToggleButtonGroup size="small" {...control} aria-label="Small sizes"> {children} </ToggleButtonGroup> <ToggleButtonGroup {...control} aria-label="Medium sizes"> {children} </ToggleButtonGroup> <ToggleButtonGroup size="large" {...control} aria-label="Large sizes"> {children} </ToggleButtonGroup> </Stack> ); } ``` ## Color ```tsx import * as React from 'react'; import ToggleButton from '@mui/material/ToggleButton'; import ToggleButtonGroup from '@mui/material/ToggleButtonGroup'; export default function ColorToggleButton() { const [alignment, setAlignment] = React.useState('web'); const handleChange = ( event: React.MouseEvent<HTMLElement>, newAlignment: string, ) => { setAlignment(newAlignment); }; return ( <ToggleButtonGroup color="primary" value={alignment} exclusive onChange={handleChange} aria-label="Platform" > <ToggleButton value="web">Web</ToggleButton> <ToggleButton value="android">Android</ToggleButton> <ToggleButton value="ios">iOS</ToggleButton> </ToggleButtonGroup> ); } ``` ## Vertical buttons The buttons can be stacked vertically with the `orientation` prop set to "vertical". ```tsx import * as React from 'react'; import ViewListIcon from '@mui/icons-material/ViewList'; import ViewModuleIcon from '@mui/icons-material/ViewModule'; import ViewQuiltIcon from '@mui/icons-material/ViewQuilt'; import ToggleButton from '@mui/material/ToggleButton'; import ToggleButtonGroup from '@mui/material/ToggleButtonGroup'; export default function VerticalToggleButtons() { const [view, setView] = React.useState('list'); const handleChange = (event: React.MouseEvent<HTMLElement>, nextView: string) => { setView(nextView); }; return ( <ToggleButtonGroup orientation="vertical" value={view} exclusive onChange={handleChange} > <ToggleButton value="list" aria-label="list"> <ViewListIcon /> </ToggleButton> <ToggleButton value="module" aria-label="module"> <ViewModuleIcon /> </ToggleButton> <ToggleButton value="quilt" aria-label="quilt"> <ViewQuiltIcon /> </ToggleButton> </ToggleButtonGroup> ); } ``` ## Enforce value set If you want to enforce that at least one button must be active, you can adapt your handleChange function. ```jsx const handleAlignment = (event, newAlignment) => { if (newAlignment !== null) { setAlignment(newAlignment); } }; const handleDevices = (event, newDevices) => { if (newDevices.length) { setDevices(newDevices); } }; ``` ```tsx import * as React from 'react'; import FormatAlignLeftIcon from '@mui/icons-material/FormatAlignLeft'; import FormatAlignCenterIcon from '@mui/icons-material/FormatAlignCenter'; import FormatAlignRightIcon from '@mui/icons-material/FormatAlignRight'; import LaptopIcon from '@mui/icons-material/Laptop'; import TvIcon from '@mui/icons-material/Tv'; import PhoneAndroidIcon from '@mui/icons-material/PhoneAndroid'; import Stack from '@mui/material/Stack'; import ToggleButton from '@mui/material/ToggleButton'; import ToggleButtonGroup from '@mui/material/ToggleButtonGroup'; export default function ToggleButtonNotEmpty() { const [alignment, setAlignment] = React.useState('left'); const [devices, setDevices] = React.useState(() => ['phone']); const handleAlignment = ( event: React.MouseEvent<HTMLElement>, newAlignment: string | null, ) => { if (newAlignment !== null) { setAlignment(newAlignment); } }; const handleDevices = ( event: React.MouseEvent<HTMLElement>, newDevices: string[], ) => { if (newDevices.length) { setDevices(newDevices); } }; return ( <Stack direction="row" spacing={4}> <ToggleButtonGroup value={alignment} exclusive onChange={handleAlignment} aria-label="text alignment" > <ToggleButton value="left" aria-label="left aligned"> <FormatAlignLeftIcon /> </ToggleButton> <ToggleButton value="center" aria-label="centered"> <FormatAlignCenterIcon /> </ToggleButton> <ToggleButton value="right" aria-label="right aligned"> <FormatAlignRightIcon /> </ToggleButton> </ToggleButtonGroup> <ToggleButtonGroup value={devices} onChange={handleDevices} aria-label="device" > <ToggleButton value="laptop" aria-label="laptop"> <LaptopIcon /> </ToggleButton> <ToggleButton value="tv" aria-label="tv"> <TvIcon /> </ToggleButton> <ToggleButton value="phone" aria-label="phone"> <PhoneAndroidIcon /> </ToggleButton> </ToggleButtonGroup> </Stack> ); } ``` ## Standalone toggle button ```tsx import * as React from 'react'; import CheckIcon from '@mui/icons-material/Check'; import ToggleButton from '@mui/material/ToggleButton'; export default function StandaloneToggleButton() { const [selected, setSelected] = React.useState(false); return ( <ToggleButton value="check" selected={selected} onChange={() => setSelected((prevSelected) => !prevSelected)} aria-label="mark as done" > <CheckIcon /> </ToggleButton> ); } ``` ## Customization Here is an example of customizing the component. You can learn more about this in the [overrides documentation page](/material-ui/customization/how-to-customize/). ```tsx import * as React from 'react'; import { styled } from '@mui/material/styles'; import FormatAlignLeftIcon from '@mui/icons-material/FormatAlignLeft'; import FormatAlignCenterIcon from '@mui/icons-material/FormatAlignCenter'; import FormatAlignRightIcon from '@mui/icons-material/FormatAlignRight'; import FormatAlignJustifyIcon from '@mui/icons-material/FormatAlignJustify'; import FormatBoldIcon from '@mui/icons-material/FormatBold'; import FormatItalicIcon from '@mui/icons-material/FormatItalic'; import FormatUnderlinedIcon from '@mui/icons-material/FormatUnderlined'; import FormatColorFillIcon from '@mui/icons-material/FormatColorFill'; import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown'; import Divider from '@mui/material/Divider'; import Paper from '@mui/material/Paper'; import ToggleButton from '@mui/material/ToggleButton'; import ToggleButtonGroup, { toggleButtonGroupClasses, } from '@mui/material/ToggleButtonGroup'; const StyledToggleButtonGroup = styled(ToggleButtonGroup)(({ theme }) => ({ [`& .${toggleButtonGroupClasses.grouped}`]: { margin: theme.spacing(0.5), border: 0, borderRadius: theme.shape.borderRadius, [`&.${toggleButtonGroupClasses.disabled}`]: { border: 0, }, }, [`& .${toggleButtonGroupClasses.middleButton},& .${toggleButtonGroupClasses.lastButton}`]: { marginLeft: -1, borderLeft: '1px solid transparent', }, })); export default function CustomizedDividers() { const [alignment, setAlignment] = React.useState('left'); const [formats, setFormats] = React.useState(() => ['italic']); const handleFormat = ( event: React.MouseEvent<HTMLElement>, newFormats: string[], ) => { setFormats(newFormats); }; const handleAlignment = ( event: React.MouseEvent<HTMLElement>, newAlignment: string, ) => { setAlignment(newAlignment); }; return ( <div> <Paper elevation={0} sx={(theme) => ({ display: 'flex', border: `1px solid ${theme.palette.divider}`, flexWrap: 'wrap', })} > <StyledToggleButtonGroup size="small" value={alignment} exclusive onChange={handleAlignment} aria-label="text alignment" > <ToggleButton value="left" aria-label="left aligned"> <FormatAlignLeftIcon /> </ToggleButton> <ToggleButton value="center" aria-label="centered"> <FormatAlignCenterIcon /> </ToggleButton> <ToggleButton value="right" aria-label="right aligned"> <FormatAlignRightIcon /> </ToggleButton> <ToggleButton value="justify" aria-label="justified" disabled> <FormatAlignJustifyIcon /> </ToggleButton> </StyledToggleButtonGroup> <Divider flexItem orientation="vertical" sx={{ mx: 0.5, my: 1 }} /> <StyledToggleButtonGroup size="small" value={formats} onChange={handleFormat} aria-label="text formatting" > <ToggleButton value="bold" aria-label="bold"> <FormatBoldIcon /> </ToggleButton> <ToggleButton value="italic" aria-label="italic"> <FormatItalicIcon /> </ToggleButton> <ToggleButton value="underlined" aria-label="underlined"> <FormatUnderlinedIcon /> </ToggleButton> <ToggleButton value="color" aria-label="color" disabled> <FormatColorFillIcon /> <ArrowDropDownIcon /> </ToggleButton> </StyledToggleButtonGroup> </Paper> </div> ); } ``` ### Spacing The demos below show how to adjust spacing between toggle buttons in horizontal and vertical orientations. #### Horizontal Spacing ```tsx import * as React from 'react'; import FormatAlignLeftIcon from '@mui/icons-material/FormatAlignLeft'; import FormatAlignCenterIcon from '@mui/icons-material/FormatAlignCenter'; import FormatAlignRightIcon from '@mui/icons-material/FormatAlignRight'; import FormatAlignJustifyIcon from '@mui/icons-material/FormatAlignJustify'; import ToggleButton, { toggleButtonClasses } from '@mui/material/ToggleButton'; import ToggleButtonGroup, { toggleButtonGroupClasses, } from '@mui/material/ToggleButtonGroup'; import { styled } from '@mui/material/styles'; const StyledToggleButtonGroup = styled(ToggleButtonGroup)(({ theme }) => ({ gap: '2rem', [`& .${toggleButtonGroupClasses.firstButton}, & .${toggleButtonGroupClasses.middleButton}`]: { borderTopRightRadius: (theme.vars || theme).shape.borderRadius, borderBottomRightRadius: (theme.vars || theme).shape.borderRadius, }, [`& .${toggleButtonGroupClasses.lastButton}, & .${toggleButtonGroupClasses.middleButton}`]: { borderTopLeftRadius: (theme.vars || theme).shape.borderRadius, borderBottomLeftRadius: (theme.vars || theme).shape.borderRadius, borderLeft: `1px solid ${(theme.vars || theme).palette.divider}`, }, [`& .${toggleButtonGroupClasses.lastButton}.${toggleButtonClasses.disabled}, & .${toggleButtonGroupClasses.middleButton}.${toggleButtonClasses.disabled}`]: { borderLeft: `1px solid ${(theme.vars || theme).palette.action.disabledBackground}`, }, })); export default function HorizontalSpacingToggleButton() { const [alignment, setAlignment] = React.useState<string | null>('left'); const handleAlignment = ( event: React.MouseEvent<HTMLElement>, newAlignment: string | null, ) => { setAlignment(newAlignment); }; return ( <StyledToggleButtonGroup value={alignment} exclusive onChange={handleAlignment} aria-label="text alignment" > <ToggleButton value="left" aria-label="left aligned"> <FormatAlignLeftIcon /> </ToggleButton> <ToggleButton value="center" aria-label="centered"> <FormatAlignCenterIcon /> </ToggleButton> <ToggleButton value="right" aria-label="right aligned"> <FormatAlignRightIcon /> </ToggleButton> <ToggleButton value="justify" aria-label="justified" disabled> <FormatAlignJustifyIcon /> </ToggleButton> </StyledToggleButtonGroup> ); } ``` #### Vertical Spacing ```tsx import * as React from 'react'; import FormatAlignLeftIcon from '@mui/icons-material/FormatAlignLeft'; import FormatAlignCenterIcon from '@mui/icons-material/FormatAlignCenter'; import FormatAlignRightIcon from '@mui/icons-material/FormatAlignRight'; import FormatAlignJustifyIcon from '@mui/icons-material/FormatAlignJustify'; import ToggleButton, { toggleButtonClasses } from '@mui/material/ToggleButton'; import ToggleButtonGroup, { toggleButtonGroupClasses, } from '@mui/material/ToggleButtonGroup'; import { styled } from '@mui/material/styles'; const StyledToggleButtonGroup = styled(ToggleButtonGroup)(({ theme }) => ({ gap: '2rem', [`& .${toggleButtonGroupClasses.firstButton}, & .${toggleButtonGroupClasses.middleButton}`]: { borderBottomRightRadius: (theme.vars || theme).shape.borderRadius, borderBottomLeftRadius: (theme.vars || theme).shape.borderRadius, }, [`& .${toggleButtonGroupClasses.lastButton}, & .${toggleButtonGroupClasses.middleButton}`]: { borderTopRightRadius: (theme.vars || theme).shape.borderRadius, borderTopLeftRadius: (theme.vars || theme).shape.borderRadius, borderTop: `1px solid ${(theme.vars || theme).palette.divider}`, }, [`& .${toggleButtonGroupClasses.lastButton}.${toggleButtonClasses.disabled}, & .${toggleButtonGroupClasses.middleButton}.${toggleButtonClasses.disabled}`]: { borderTop: `1px solid ${(theme.vars || theme).palette.action.disabledBackground}`, }, })); export default function VerticalSpacingToggleButton() { const [alignment, setAlignment] = React.useState<string | null>('left'); const handleAlignment = ( event: React.MouseEvent<HTMLElement>, newAlignment: string | null, ) => { setAlignment(newAlignment); }; return ( <StyledToggleButtonGroup value={alignment} exclusive onChange={handleAlignment} aria-label="text alignment" orientation="vertical" > <ToggleButton value="left" aria-label="left aligned"> <FormatAlignLeftIcon /> </ToggleButton> <ToggleButton value="center" aria-label="centered"> <FormatAlignCenterIcon /> </ToggleButton> <ToggleButton value="right" aria-label="right aligned"> <FormatAlignRightIcon /> </ToggleButton> <ToggleButton value="justify" aria-label="justified" disabled> <FormatAlignJustifyIcon /> </ToggleButton> </StyledToggleButtonGroup> ); } ``` ## Accessibility ### ARIA - ToggleButtonGroup has `role="group"`. You should provide an accessible label with `aria-label="label"`, `aria-labelledby="id"` or `<label>`. - ToggleButton sets `aria-pressed="<bool>"` according to the button state. You should label each button with `aria-label`. ### Keyboard The group uses a single tab stop. Use the left and right arrow keys to move focus in a horizontal group, or the up and down arrow keys in a vertical group. The <kbd>Home</kbd> and <kbd>End</kbd> keys move focus to the first and last enabled buttons. Focus movement wraps, skips disabled buttons, and does not change the selected value. Press <kbd>Space</kbd> or <kbd>Enter</kbd> to toggle the focused button. # ToggleButton API ## Demos For examples and details on the usage of this React component, visit the component demo pages: - [Toggle Button](https://mui.com/material-ui/react-toggle-button/) ## Import ```jsx import ToggleButton from '@mui/material/ToggleButton'; // or import { ToggleButton } from '@mui/material'; ``` ## Props | Name | Type | Default | Required | Description | |------|------|---------|----------|-------------| | value | `any` | - | Yes | | | children | `node` | - | No | | | classes | `object` | - | No | Override or extend the styles applied to the component. | | color | `'standard' \| 'primary' \| 'secondary' \| 'error' \| 'info' \| 'success' \| 'warning' \| string` | `'standard'` | No | | | disabled | `bool` | `false` | No | | | disableFocusRipple | `bool` | `false` | No | | | disableRipple | `bool` | `false` | No | | | fullWidth | `bool` | `false` | No | | | onChange | `function(event: React.MouseEvent<HTMLElement>, value: any) => void` | - | No | | | onClick | `function(event: React.MouseEvent<HTMLElement>, value: any) => void` | - | No | | | selected | `bool` | - | No | | | size | `'small' \| 'medium' \| 'large' \| string` | `'medium'` | No | | | sx | `Array<func \| object \| bool> \| func \| object` | - | No | The system prop that allows defining system overrides as well as additional CSS styles. | > **Note**: The `ref` is forwarded to the root element (HTMLButtonElement). > Any other props supplied will be provided to the root element ([ButtonBase](https://mui.com/material-ui/api/button-base/)). ## Inheritance While not explicitly documented above, the props of the [ButtonBase](https://mui.com/material-ui/api/button-base/) component are also available on ToggleButton. ## Theme default props You can use `MuiToggleButton` to change the default props of this component with the theme. ## CSS ### Rule name | Global class | Rule name | Description | |--------------|-----------|-------------| | `.Mui-disabled` | - | State class applied to the root element if `disabled={true}`. | | - | fullWidth | Styles applied to the root element if `fullWidth={true}`. | | - | primary | State class applied to the root element if `color="primary"`. | | - | root | Styles applied to the root element. | | - | secondary | State class applied to the root element if `color="secondary"`. | | `.Mui-selected` | - | State class applied to the root element if `selected={true}`. | | - | sizeLarge | Styles applied to the root element if `size="large"`. | | - | sizeMedium | Styles applied to the root element if `size="medium"`. | | - | sizeSmall | Styles applied to the root element if `size="small"`. | | - | standard | State class applied to the root element if `color="standard"`. | ## Source code If you did not find the information on this page, consider having a look at the implementation of the component for more detail. - [/packages/mui-material/src/ToggleButton/ToggleButton.js](https://github.com/mui/material-ui/tree/HEAD/packages/mui-material/src/ToggleButton/ToggleButton.js) # ToggleButtonGroup API ## Demos For examples and details on the usage of this React component, visit the component demo pages: - [Toggle Button](https://mui.com/material-ui/react-toggle-button/) ## Import ```jsx import ToggleButtonGroup from '@mui/material/ToggleButtonGroup'; // or import { ToggleButtonGroup } from '@mui/material'; ``` ## Props | Name | Type | Default | Required | Description | |------|------|---------|----------|-------------| | children | `node` | - | No | | | classes | `object` | - | No | Override or extend the styles applied to the component. | | color | `'standard' \| 'primary' \| 'secondary' \| 'error' \| 'info' \| 'success' \| 'warning' \| string` | `'standard'` | No | | | disabled | `bool` | `false` | No | | | exclusive | `bool` | `false` | No | | | fullWidth | `bool` | `false` | No | | | onChange | `function(event: React.MouseEvent<HTMLElement>, value: any) => void` | - | No | | | orientation | `'horizontal' \| 'vertical'` | `'horizontal'` | No | | | size | `'small' \| 'medium' \| 'large' \| string` | `'medium'` | No | | | sx | `Array<func \| object \| bool> \| func \| object` | - | No | The system prop that allows defining system overrides as well as additional CSS styles. | | value | `any` | - | No | | > **Note**: The `ref` is forwarded to the root element (HTMLDivElement). > Any other props supplied will be provided to the root element (native element). ## Theme default props You can use `MuiToggleButtonGroup` to change the default props of this component with the theme. ## CSS ### Rule name | Global class | Rule name | Description | |--------------|-----------|-------------| | `.Mui-disabled` | - | State class applied to the root element if `disabled={true}`. | | - | firstButton | Styles applied to the first button in the toggle button group. | | - | fullWidth | Styles applied to the root element if `fullWidth={true}`. | | - | grouped | Styles applied to the children. | | - | horizontal | Styles applied to the root element if `orientation="horizontal"`. | | - | lastButton | Styles applied to the last button in the toggle button group. | | - | middleButton | Styles applied to buttons in the middle of the toggle button group. | | - | root | Styles applied to the root element. | | `.Mui-selected` | - | State class applied to the root element if `selected={true}`. | | - | vertical | Styles applied to the root element if `orientation="vertical"`. | ## Source code If you did not find the information on this page, consider having a look at the implementation of the component for more detail. - [/packages/mui-material/src/ToggleButtonGroup/ToggleButtonGroup.js](https://github.com/mui/material-ui/tree/HEAD/packages/mui-material/src/ToggleButtonGroup/ToggleButtonGroup.js)