@douyinfe/semi-ui
Version:
A modern, comprehensive, flexible design system and UI library. Connect DesignOps & DevOps. Quickly build beautiful React apps. Maintained by Douyin-fe team.
662 lines (551 loc) • 30.8 kB
Markdown
---
localeCode: en-US
order: 22
category: Input
title: Button
subTitle: Button
icon: doc-button
dir: column
brief: Users use buttons to trigger an operation or jump.
---
## Demos
### How to import
```jsx import
import { Button, SplitButtonGroup } from '@douyinfe/semi-ui';
```
### Button Type
Buttons support the following types:
- Primary button ("primary", default)
- Secondary button ("secondary")
- Tertiary button ("tertiary")
- Warning button ("warning")
- Danger button ("danger")
```jsx live=true dir="column"
import React from 'react';
import { Button } from '@douyinfe/semi-ui';
function ButtonDemo() {
return (
<div className="btn-margin-right">
<Button>Primary Button</Button>
<Button type="secondary">Secondary Button</Button>
<Button type="tertiary">Tertiary Button</Button>
<Button type="warning">Warning Button</Button>
<Button type="danger">Danger Button</Button>
</div>
);
}
```
#### About the Font Color
[CSS Variables](https://developer.mozilla.org/zh-CN/docs/Web/CSS/Using_CSS_custom_properties) are used with the button:
- `var(--semi-color-primary)`: main
- `var(--semi-color-secondary)`: secondary
- `var(--semi-color-tertiary)`: third
- `var(--semi-color-warning)`: warning
- `var(--semi-color-danger)`: danger
You can define your elements directly using these theme colors.
```jsx live=true dir="column"
import React from 'react';
function ButtonDemo() {
const types = [['primary', 'primary'], ['secondary', 'secondary'], ['tertiary', 'tertiary'], ['warning', 'warning'], ['danger', 'danger']];
return (
<article>
{types.map((type, index) => (
<strong key={index} style={{ color: `var(--semi-color-${Array.isArray(type) ? type[0] : type})`, marginRight: 10 }}>{Array.isArray(type) ? type[1]: type}</strong>
))}
</article>
);
}
```
### Button Theme
The themes currently available are:
- `light`: light background
- `solid`: dark background
- `borderless`: no background
- `outline`: border mode
The default theme is `light`
#### Light Background
```jsx live=true dir="column"
import React from 'react';
import { Button } from '@douyinfe/semi-ui';
function ButtonDemo() {
const themes = [['light', 'light']];
const types = [['primary', 'primary'], ['secondary', 'secondary'], ['tertiary', 'tertiary'], ['warning', 'warning'], ['danger', 'danger']];
return (
<div>{
themes.map((theme, idxTheme) => (
<div key={idxTheme}>
<ul style={{ listStyle: 'none', display: 'flex', margin: 0, padding: 0 }}>
{types.map((type, idxType) => (
<li key={'' + idxTheme + idxType} style={{ margin: 10 }}>
<Button
theme={theme[0]}
type={type[0]}
>
{theme[1]} {type[1]}
</Button>
</li>)
)}
</ul>
</div>))
}
</div>
);
}
```
#### Dark Background
```jsx live=true dir="column"
import React from 'react';
import { Button } from '@douyinfe/semi-ui';
function ButtonDemo() {
const themes = [['solid', 'solid']];
const types = [['primary', 'primary'], ['secondary', 'secondary'], ['tertiary', 'tertiary'], ['warning', 'warning'], ['danger', 'danger']];
return (
<div>{
themes.map((theme, idxTheme) => (
<div key={idxTheme}>
<ul style={{ listStyle: 'none', display: 'flex', margin: 0, padding: 0 }}>
{types.map((type, idxType) => (
<li key={'' + idxTheme + idxType} style={{ margin: 10 }}>
<Button
theme={theme[0]}
type={type[0]}
>
{theme[1]} {type[1]}
</Button>
</li>)
)}
</ul>
</div>))
}
</div>
);
}
```
#### No Background
```jsx live=true dir="column"
import React from 'react';
import { Button } from '@douyinfe/semi-ui';
function ButtonDemo() {
const themes = [['borderless', 'borderless']];
const types = [['primary', 'primary'], ['secondary', 'secondary'], ['tertiary', 'tertiary'], ['warning', 'warning'], ['danger', 'danger']];
return (
<div>{
themes.map((theme, idxTheme) => (
<div key={idxTheme}>
<ul style={{ listStyle: 'none', display: 'flex', margin: 0, padding: 0 }}>
{types.map((type, idxType) => (
<li key={'' + idxTheme + idxType} style={{ margin: 10 }}>
<Button
theme={theme[0]}
type={type[0]}
>
{theme[1]} {type[1]}
</Button>
</li>)
)}
</ul>
</div>))
}
</div>
);
}
```
#### Border Mode
```jsx live=true dir="column"
import React from 'react';
import { Button } from '@douyinfe/semi-ui';
function ButtonDemo() {
const themes = [['outline', 'outline']];
const types = [['primary', 'primary'], ['secondary', 'secondary'], ['tertiary', 'tertiary'], ['warning', 'warning'], ['danger', 'danger']];
return (
<div>{
themes.map((theme, idxTheme) => (
<div key={idxTheme}>
<ul style={{ listStyle: 'none', display: 'flex', margin: 0, padding: 0 }}>
{types.map((type, idxType) => (
<li key={'' + idxTheme + idxType} style={{ margin: 10 }}>
<Button
theme={theme[0]}
type={type[0]}
>
{theme[1]} {type[1]}
</Button>
</li>)
)}
</ul>
</div>))
}
</div>
);
}
```
### Size
Three sizes are defined by default:
- Big: "Large"
- Default: "default."
- Small: "Small"
```jsx live=true dir="column"
import React from 'react';
import { Button } from '@douyinfe/semi-ui';
function ButtonDemo() {
return (
<div>
<Button size='large' style={{ marginRight: 8 }}>large</Button>
<Button size='default' style={{ marginRight: 8 }}>default</Button>
<Button size='small'>small</Button>
</div>
);
}
```
### Block Button
The block button has a predefined width, and its width is independent of the width of the contents of the button.
```jsx live=true dir="column"
import React from 'react';
import { Button } from '@douyinfe/semi-ui';
function ButtonDemo() {
return (
<div>
<Button block>block button</Button>
</div>
);
}
```
### Icon Button
An icon that defines a button.
```jsx live=true dir="column"
import React from 'react';
import { Button } from '@douyinfe/semi-ui';
import { IconCamera, IconSidebar, IconChevronDown } from '@douyinfe/semi-icons';
function ButtonDemo() {
return (
<div>
<strong>Default Status: </strong>
<Button icon={<IconCamera />} aria-label="Screenshot" />
<br/><br/>
<strong>Disabled Status:</strong>
<Button icon={<IconCamera />} aria-label="Screenshot"/>
<br/><br/>
<strong>With Type: </strong>
<span className="btn-margin-right">
<Button type="primary" icon={<IconCamera />} aria-label="Screenshot"/>
<Button type="secondary" icon={<IconCamera />} aria-label="Screenshot"/>
<Button type="warning" icon={<IconCamera />} aria-label="Screenshot"/>
<Button type="danger" icon={<IconCamera />} aria-label="Screenshot"/>
</span>
<br/><br/>
<strong>Change Theme: </strong>
<Button icon={<IconCamera />} theme="solid" style={{ marginRight: 10 }} aria-label="Screenshot"/>
<Button icon={<IconCamera />} theme="light" aria-label="Screenshot"/>
<br/><br/>
<strong>Change Icon Position: </strong>
<Button icon={<IconSidebar />} theme="solid" style={{ marginRight: 10 }}>Collapse</Button>
<Button icon={<IconChevronDown />} theme="solid" iconPosition="right">Expand Options</Button>
<br/><br/>
</div>
);
}
```
### Link Button
We recommend using Typography to achieve link text button. Refer to [Typography](/en-US/basic/typography) for more information.
```jsx live=true
import React from 'react';
import { Typography } from '@douyinfe/semi-ui';
import { IconLink } from '@douyinfe/semi-icons';
function Demo() {
const { Text } = Typography;
return (
<div>
<Text link={{ href: 'https://semi.design/' }}>Link</Text>
<br />
<br />
<Text link={{ href: 'https://semi.design/' }}>Open Website</Text>
<br />
<br />
<Text link icon={<IconLink />} underline>Link</Text>
</div>
);
}
```
### Prohibited Status
```jsx live=true dir="column"
import React from 'react';
import { Button } from '@douyinfe/semi-ui';
function ButtonDemo() {
return (
<div>
<Button disabled>Disabled</Button>
<Button disabled theme="borderless">No background and disabled</Button>
<Button disabled theme="light">Light and disbaled</Button>
<Button disabled theme="borderless" type="primary">No background, primary and disabled</Button>
<Button disabled theme="solid" type="warning">Solid, warning and disabled</Button>
</div>
);
}
```
### Loading State
The button supports the Loading state, by setting the loading parameter value to true, note: the state priority is higher than the loading state.
```jsx live=true dir="column"
import React, { useState } from 'react';
import { Button } from '@douyinfe/semi-ui';
import { IconDelete } from '@douyinfe/semi-icons';
function ButtonDemo() {
const [saveLoading, setSaveLoading] = useState(false);
const [delLoading, setDelLoading] = useState(true);
const [repLoading, setRepLoading] = useState(true);
const reset = status => {
status = !!status;
setSaveLoading(status);
setDelLoading(status);
setRepLoading(status);
};
return (
<div>
<div>
<div className="btn-margin-right" style={{ display: 'inline-flex', alignItems: 'center', paddingBottom: 14 }}>
<Button onClick={() => reset(false)}>Stop loading</Button>
<Button onClick={() => reset(true)}>Start loading</Button>
</div>
</div>
<hr/>
<Button loading={saveLoading} onClick={() => setSaveLoading(true)} style={{ marginRight: 14 }}>Save</Button>
<Button loading={delLoading} icon={<IconDelete />} type="danger" onClick={() => setDelLoading(true)} style={{ marginRight: 14 }}>Delete</Button>
<div style={{ width: 200, display: 'inline-block' }}>
<Button loading={repLoading} type="warning" block theme="solid" onClick={() => setRepLoading(true)}>Revoke</Button>
</div>
</div>
);
}
```
### AI style - Colorful buttons
Set `colorful` to get colorful buttons. Colorful buttons support all `theme`, and `type` only supports `primary` and `tertiary`.
```jsx live=true dir="column"
import React, { useState } from 'react';
import { Button } from '@douyinfe/semi-ui';
import { IconAIFilledLevel1, IconAIFilledLevel2, IconAIFilledLevel3 } from '@douyinfe/semi-icons';
function ButtonDemo() {
return (['Colorful', undefined].map(content => (<div
key={content}
style={{ display: 'flex', rowGap: 16, marginTop: 20, marginLeft: 10, flexDirection: 'column' }}
>
<div style={{ display: 'flex', columnGap: 16 }}>
<Button colorful theme="solid" type="primary" icon={<IconAIFilledLevel1 />}>{content}</Button>
<Button colorful theme="solid" type="primary" loading >{content}</Button>
<Button colorful theme="solid" type="primary" icon={<IconAIFilledLevel1 />} disabled >{content}</Button>
<Button colorful theme="solid" type="tertiary" icon={<IconAIFilledLevel3 />}>{content}</Button>
<Button colorful theme="solid" type="tertiary" loading >{content}</Button>
<Button colorful theme="solid" type="tertiary" icon={<IconAIFilledLevel3 />} disabled >{content}</Button>
</div>
<div style={{ display: 'flex', columnGap: 16 }}>
<Button colorful theme="light" type="primary" icon={<IconAIFilledLevel3 />}>{content}</Button>
<Button colorful theme="light" type="primary" loading >{content}</Button>
<Button colorful theme="light" type="primary" icon={<IconAIFilledLevel3 />} disabled >{content}</Button>
<Button colorful theme="light" type="tertiary" icon={<IconAIFilledLevel2 />}>{content}</Button>
<Button colorful theme="light" type="tertiary" loading >{content}</Button>
<Button colorful theme="light" type="tertiary" icon={<IconAIFilledLevel2 />} disabled >{content}</Button>
</div>
<div style={{ display: 'flex', columnGap: 16 }}>
<Button colorful theme="outline" type="primary" icon={<IconAIFilledLevel1 />}>{content}</Button>
<Button colorful theme="outline" type="primary" loading >{content}</Button>
<Button colorful theme="outline" type="primary" icon={<IconAIFilledLevel1 />} disabled >{content}</Button>
<Button colorful theme="outline" type="tertiary" icon={<IconAIFilledLevel2 />}>{content}</Button>
<Button colorful theme="outline" type="tertiary" loading >{content}</Button>
<Button colorful theme="outline" type="tertiary" icon={<IconAIFilledLevel2 />} disabled >{content}</Button>
</div>
<div style={{ display: 'flex', columnGap: 16 }}>
<Button colorful theme="borderless" type="primary" icon={<IconAIFilledLevel3 />}>{content}</Button>
<Button colorful theme="borderless" type="primary" loading >{content}</Button>
<Button colorful theme="borderless" type="primary" icon={<IconAIFilledLevel3 />} disabled >{content}</Button>
<Button colorful theme="borderless" type="tertiary" icon={<IconAIFilledLevel2 />}>{content}</Button>
<Button colorful theme="borderless" type="tertiary" loading >{content}</Button>
<Button colorful theme="borderless" type="tertiary" icon={<IconAIFilledLevel2 />} disabled >{content}</Button>
</div>
</div>)));
}
```
### Button Combination
You can put multiple buttons in `ButtonGroup` In the container, by setting `size`, `disabled`, `type` You can uniformly set the button size in the button combination, whether disabled and type.
#### Combined Dimensions
```jsx live=true dir="column"
import React from 'react';
import { Button, ButtonGroup } from '@douyinfe/semi-ui';
function ButtonDemo() {
const sizes = ['large', 'default', 'small'];
return (
<div style={{ display: 'flex' }}>
{sizes.map(size => (
<div style={{ marginRight: 10 }} key={size}>
<ButtonGroup size={size} aria-label="Operate button group">
<Button>Copy</Button>
<Button>Search</Button>
<Button>Cut</Button>
</ButtonGroup>
</div>
))}
</div>
);
}
```
#### Combined Disabled
```jsx live=true dir="column"
import React from 'react';
import { Button, ButtonGroup } from '@douyinfe/semi-ui';
function ButtonDemo() {
return (
<div style={{ display: 'flex' }}>
<div style={{ marginRight: 10 }}>
<ButtonGroup disabled>
<Button>Copy</Button>
<Button>Search</Button>
<Button>Cut</Button>
</ButtonGroup>
</div>
</div>
);
}
```
#### Combined Type
```jsx live=true dir="column"
import React from 'react';
import { Button, ButtonGroup } from '@douyinfe/semi-ui';
function ButtonDemo() {
const types = ['primary', 'secondary', 'tertiary', 'warning', 'danger'];
return (
<div style={{ display: 'flex' }}>
{types.map(type => (
<div style={{ marginRight: 10 }} key={type}>
<ButtonGroup type={type} aria-label="Operate button group">
<Button>Copy</Button>
<Button>Search</Button>
<Button>Cut</Button>
</ButtonGroup>
</div>
))}
</div>
);
}
```
### Split Button Group
**V1.12.0**
In the scene where `Button` and `Dropdown` are combined, split buttons can be used. The split buttons add the space between the buttons and change the rounded corners of the buttons.
#### Basic Usage
```jsx live=true dir="column"
import React, { useState } from 'react';
import { SplitButtonGroup, Dropdown, Button } from '@douyinfe/semi-ui';
import { IconTreeTriangleDown } from '@douyinfe/semi-icons';
function SplitButtonDemo(){
const menu = [
{ node: 'title', name: 'Title' },
{ node: 'item', name: 'Edit', onClick: () => console.log('Edit clicked') },
{ node: 'item', name: 'Reset', type: 'secondary' },
{ node: 'divider' },
{ node: 'item', name: 'Create', type: 'tertiary' },
{ node: 'item', name: 'Copy', type: 'warning' },
{ node: 'divider' },
{ node: 'item', name: 'Delete', type: 'danger' },
];
const [btnVisible, setBtnVisible] = useState({
1: false,
2: false,
3: false
});
const handleVisibleChange = (key, visible)=>{
newBtnVisible = { ...btnVisible };
newBtnVisible[key] = visible;
setBtnVisible(newBtnVisible);
};
return (
<div>
<SplitButtonGroup style={{ marginRight: 10 }} aria-label="Project operate button group">
<Button theme="solid" type="primary">SplitButton</Button>
<Dropdown onVisibleChange={(v)=>handleVisibleChange(1, v)} menu={menu} trigger="click" position="bottomRight">
<Button style={btnVisible[1]?{ background: 'var(--semi-color-primary-hover)', padding: '8px 4px' }:{ padding: '8px 4px' }} theme="solid" type="primary" icon={<IconTreeTriangleDown size="small" />}></Button>
</Dropdown>
</SplitButtonGroup>
<SplitButtonGroup style={{ marginRight: 10 }} aria-label="Project operate button group">
<Button theme="light" type="primary">SplitButton</Button>
<Dropdown onVisibleChange={(v)=>handleVisibleChange(2, v)} menu={menu} trigger="click" position="bottomRight">
<Button style={btnVisible[2]?{ background: 'var(--semi-color-fill-1)', padding: '8px 4px' }:{ padding: '8px 4px' }} theme="light" type="primary" icon={<IconTreeTriangleDown size="small" />}></Button>
</Dropdown>
</SplitButtonGroup>
<SplitButtonGroup aria-label="Project operate button group">
<Button style={btnVisible[3]?{ background: 'var(--semi-color-fill-0)' }:null} theme="borderless" type="primary">SplitButton</Button>
<Dropdown onVisibleChange={(v)=>handleVisibleChange(3, v)} menu={menu} trigger="click" position="bottomRight">
<Button style={btnVisible[3]?{ background: 'var(--semi-color-fill-1)', padding: '8px 4px' }:{ padding: '8px 4px' }} theme="borderless" type="primary" icon={<IconTreeTriangleDown size="small" />}></Button>
</Dropdown>
</SplitButtonGroup>
</div>
);
}
```
## API Reference
### Button
| Properties | Instructions | Type | Default |
| ------------------- |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -------------------------------- |-----------|
| aria-label | Label of the button | string | - |
| block | Set the button to the block level button | boolean | false |
| className | Class name | string | |
| contentClassName | content className | string | - |
| colorful | Colorful buttons, supported since version 2.86.0 | boolean | false |
| disabled | Prohibited status | boolean | false |
| htmlType | Set the `button` native `type` value, optional values: `"button"`, `"reset"`, `"submit"` | string | "button" |
| icon | Icon | ReactNode | |
| iconPosition | Icon location, optional value: `"left"`\|`"right"` | string | `"left"` |
| loading | Loading state | boolean | false |
| noHorizontalPadding | Set whether to remove the inner margin in the horizontal direction, only valid for iconButton, optional: `true` (equivalent to \["left", "right"\]), "left", "right", \["left", "right"\] | boolean\|string\| Array<string\> | false |
| size | Button size, optional value: `"large"`,`"default"`,`"small"` | string | "default" |
| style | Custom style | CSSProperties | |
| theme | Button theme, optional value: `"solid"` (with background color), `"borderless"` (no background color), `"light"` (light background color), `"outline"`(Border Mode) | string | "light" |
| type | Type, optional values: `"primary"`,`"secondary"`, `"tertiary"`, `"warning"`, `"danger"` | string | "primary" |
| onClick | Click event | Function(MouseEvent) | |
| onMouseDown | Mouse down | Function(MouseEvent) | |
| onMouseEnter | Mouse Enter | Function(MouseEvent) | |
| onMouseLeave | Mouse Leave | Function(MouseEvent) | |
### ButtonGroup
| Properties | Instructions | Type | Default | Version |
| ---------- |--------------------------------------------------------------------------------------------------------------------------------------------------| ------- | --------- |---------|
| aria-label | Label of the button group | string | - | |
| className | Custom class name | string | - | |
| colorful | Colorful buttons | boolean | false | 2.86.0 |
| disabled | Disabled status | boolean | false | |
| size | Button size, optional value: `"large"`,`"default"`,`"small"` | string | "default" |
| style | Custom style | CSSProperties | - | 2.20.0 |
| theme | Button theme, optional values: `"solid"` (with background color), `"borderless"` (without background color), `"light"` (light background color),`"outline"`(Border Mode) | string | "light" | |
| type | Type, optional values: `"primary"`,`"secondary"`, `"tertiary"`, `"warning"`, `"danger"` | string | "primary" |
### SplitButtonGroup **V1.12.0**
| Properties | Instructions | Type | Default |
| ----------- | ---------------------------------| -------- | --------- |
| aria-label | Label of the button group | string | - |
| className | Custom class name | string | - |
| style | Custom style | CSSProperties | - |
## Accessibility
### ARIA
- `aria-label` is used to indicate the function of the button. For icon buttons, we recommend using this attribute
- `aria-disabled` is synchronized with the disabled attribute, indicating that the button is disabled
### Keyboard and Focus
- `Button`'s focus management is consistent with native `button`, keyboard users can use `Tab` and `Shift + Tab` to switch focus
- The trigger of `Button` is the same as the native `button`, when the `button` is focused, it can be activated by `Enter` or `Space` key
- The buttons in the `ButtonGroup` are managed in the same way as the focus of a single `button`, and can be switched by `Tab` and `Shift + Tab`
## Content Guidelines
- Buttons need to be clear and predictable, users should be able to predict what will happen when they click the button
- Buttons should always start with a strong verb that encourages action
- To give the user enough context, use {verb}+{noun} content formulas on buttons; in addition to common actions like "Done", "Close", "Cancel" or "OK"
| ✅ Recommended usage | ❌ Deprecated usage |
| --- | --- |
| <div style={{ textAlign: 'center' }}><Empty image={<IllustrationNoAccess style={{ width: 150, height: 150 }} />} darkModeImage={<IllustrationNoAccessDark style={{ width: 150, height: 150 }} />} description={'No permission to view this page'}/><Button theme='solid' type='primary' style={{ marginTop: 12 }}>Apply permission</Button></div>| <div style={{ textAlign: 'center' }}><Empty image={<IllustrationNoAccess style={{ width: 150, height: 150 }} />} darkModeImage={<IllustrationNoAccessDark style={{ width: 150, height: 150 }} />} description={'No permission to view this page'}/><Button theme='solid' type='primary' style={{ marginTop: 12 }}>Apply</Button></div> |
- When the button is combined with other components, the button can only display {verb}, such as "Add", "Create", if the other components (such as Modal and Sidesheet) already provide enough context for the information
| ✅ Recommended usage | ❌ Deprecated usage |
| --- | --- |
| <img src='https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/content_guide/button-good-2.png' style={{ width: 350 }} />| <img src='https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/content_guide/button-bad-2.png' style={{ width: 350 }} /> |
- Always write in Sentence case
| ✅ Recommended usage | ❌ Deprecated usage |
| --- | --- |
| Create project | Create <br/> Create a project|
| Edit profile | Edit |
## Design Tokens
<DesignToken/>
<!-- ## Related Material
```material
5
``` -->
## Related Material
<semi-material-list code="5"></semi-material-list>