Button
Buttons let users take actions and make choices with a single tap.
Basics
import { Button } from 'tailwind-joy/components';
The Tailwind-Joy Button behaves similarly to the native HTML <button>
, so it wraps around the text displayed on its surface.
The demo below shows the three basic states available to the Button: default, disabled, and loading.
import { Box, Button } from 'tailwind-joy/components';
export function ButtonBasics() {
return (
<Box className="flex flex-wrap justify-center gap-4">
<Button>Button</Button>
<Button disabled>Disabled</Button>
<Button loading>Loading</Button>
</Box>
);
}
Disabled
Use the disabled
prop to disable interaction and focus:
import { Box, Button } from 'tailwind-joy/components';
export function ButtonDisabled() {
return (
<Box className="flex flex-wrap justify-center gap-4">
<Button disabled variant="solid">
Solid
</Button>
<Button disabled variant="soft">
Soft
</Button>
<Button disabled variant="outlined">
Outlined
</Button>
<Button disabled variant="plain">
Plain
</Button>
</Box>
);
}
Loading
Add the loading
prop to show the Button's loading state.
The Button is disabled as long as it's loading.
See Loading indicator and Loading position for customization options.
import { Box, Button } from 'tailwind-joy/components';
export function ButtonLoading() {
return (
<Box className="flex flex-wrap justify-center gap-4">
<Button loading variant="solid">
Solid
</Button>
<Button loading variant="soft">
Soft
</Button>
<Button loading variant="outlined">
Outlined
</Button>
<Button loading variant="plain">
Plain
</Button>
</Box>
);
}
Customization
Variants
The Button component supports four variants: solid
(default), soft
, outlined
, and plain
.
import { Box, Button } from 'tailwind-joy/components';
export function ButtonVariants() {
return (
<Box className="flex flex-wrap justify-center gap-4">
<Button variant="solid">Solid</Button>
<Button variant="soft">Soft</Button>
<Button variant="outlined">Outlined</Button>
<Button variant="plain">Plain</Button>
</Box>
);
}
Sizes
The Button component supports three sizes: sm
, md
(default), and lg
.
import { Box, Button } from 'tailwind-joy/components';
export function ButtonSizes() {
return (
<Box className="flex flex-wrap items-center justify-center gap-4">
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>
</Box>
);
}
Colors
The Button component supports five colors: primary
(default), neutral
, danger
, success
, and warning
.
import { Box, Button } from 'tailwind-joy/components';
export function ButtonColors() {
return (
<Box className="flex flex-wrap justify-center gap-4">
<Button color="primary">Primary</Button>
<Button color="neutral">Neutral</Button>
<Button color="danger">Danger</Button>
<Button color="success">Success</Button>
<Button color="warning">Warning</Button>
</Box>
);
}
Decorators
Use the startDecorator
and endDecorator
props to append actions and icons to either side of the Button:
import { MdAdd, MdKeyboardArrowRight } from 'react-icons/md';
import { Box, Button } from 'tailwind-joy/components';
import { iconClass } from 'tailwind-joy/utils';
export function ButtonDecorators() {
return (
<Box className="flex flex-wrap justify-center gap-4">
<Button
color="primary"
startDecorator={<MdAdd className={iconClass()} />}
>
Add to cart
</Button>
<Button
color="success"
endDecorator={<MdKeyboardArrowRight className={iconClass()} />}
>
Go to checkout
</Button>
</Box>
);
}
iconClass()
is an adapter function provided by Tailwind-Joy.
Loading indicator
The default loading indicator uses the Circular Progress component.
Use the loadingIndicator
prop to replace it with a custom indicator, as shown below:
import { Box, Button } from 'tailwind-joy/components';
export function ButtonLoadingIndicator() {
return (
<Box className="flex flex-wrap justify-center gap-4">
<Button loading>Default</Button>
<Button loading loadingIndicator="Loading...">
Custom
</Button>
</Box>
);
}
Loading position
The loadingPosition
prop sets the position of the Button's loading indicator.
It supports three values:
center
(default): The loading indicator is nested inside theloadingIndicatorCenter
slot and replaces the Button's contents when in the loading state.start
: The loading indicator replaces the starting decorator when the Button is in the loading state.end
: The loading indicator replaces the ending decorator when the Button is in the loading state.
import { MdSend } from 'react-icons/md';
import { Box, Button } from 'tailwind-joy/components';
import { iconClass } from 'tailwind-joy/utils';
export function ButtonLoadingPosition() {
return (
<Box className="flex flex-wrap justify-center gap-4">
<Button loading loadingPosition="start">
Start
</Button>
<Button
loading
loadingPosition="end"
endDecorator={<MdSend className={iconClass()} />}
>
End
</Button>
</Box>
);
}
Link Button
Buttons let users take actions, but if that action is to navigate to a new page, then an anchor tag is generally preferable over a button tag.
If you need the style of a button with the functionality of a link, then you can use the component
prop to replace the default <button>
with an <a>
, as shown below:
The text color and underline that change when hovering are in the style of docusaurus.
import { MdOpenInNew } from 'react-icons/md';
import { Button } from 'tailwind-joy/components';
import { iconClass } from 'tailwind-joy/utils';
export function ButtonLink() {
return (
<Button
component="a"
href="/docs/components/button"
target="_blank"
rel="noreferrer"
color="neutral"
variant="soft"
startDecorator={<MdOpenInNew className={iconClass()} />}
>
Open in new tab
</Button>
);
}
File upload
To create a file upload button, turn the button into a label using component="label"
and then create a visually-hidden input with type file
.
import { MdOutlineCloudUpload } from 'react-icons/md';
import { Button } from 'tailwind-joy/components';
import { iconClass } from 'tailwind-joy/utils';
function VisuallyHiddenInput() {
return (
<input
type="file"
className="
absolute bottom-0 left-0 h-px w-px overflow-hidden
whitespace-nowrap [clip-path:inset(50%)] [clip:rect(0_0_0_0)]
"
/>
);
}
export function ButtonFileUpload() {
return (
<Button
component="label"
role={undefined}
tabIndex={-1}
color="neutral"
variant="outlined"
startDecorator={<MdOutlineCloudUpload className={iconClass()} />}
>
Upload a file
<VisuallyHiddenInput />
</Button>
);
}
Icon Button
import { IconButton } from 'tailwind-joy/components';
Use the Icon Button component for a square button to house an icon with no text content.
import { MdFavoriteBorder } from 'react-icons/md';
import { Box, IconButton } from 'tailwind-joy/components';
import { iconClass } from 'tailwind-joy/utils';
export function IconButtonBasics() {
return (
<Box className="flex flex-wrap items-center justify-center gap-4">
<IconButton variant="solid">
<MdFavoriteBorder className={iconClass()} />
</IconButton>
<IconButton variant="soft">
<MdFavoriteBorder className={iconClass()} />
</IconButton>
<IconButton variant="outlined">
<MdFavoriteBorder className={iconClass()} />
</IconButton>
<IconButton variant="plain">
<MdFavoriteBorder className={iconClass()} />
</IconButton>
</Box>
);
}
Anatomy
The Button component is composed of a single root <button>
element that wraps around its contents:
<button type="button" class="tj-button-root ...">
<!-- Button contents -->
</button>
API
See the documentation below for a complete reference to all of the props available to the components mentioned here.