Implementation
Button Props
ButtonCompound Props
ButtonLink Props
Common Examples
import { Button, ButtonCompound, ButtonLink, Card } from "@servicetitan/anvil2";
function ExampleComponent() {
return (
<>
<Button onClick={console.log}>Click me</Button>
<ButtonCompound onClick={console.log}>
<Card>Click me</Card>
</ButtonCompound>
<ButtonLink href="#">Click me</ButtonLink>
</>
);
}
The Button component can be used in the same way that you would use an HTML button element, while the ButtonLink component can be used in the same way that you would use an HTML a element.The type prop can be used to alter the default functionality of the button. A common use case is to use type="submit" in order to submit the content of a form.<form onSubmit={handleSubmit}>
<TextInput name="firstName" label="First Name" required />
<Button type="submit">Submit</Button>
</form>
In general, Links should be used for navigating to other pages or website. To create a link that is styled like a button, use the ButtonLink component.<div>
<div>
<BodyText>
A project label can be attached to expense items like timesheet activities
to provide a visual representation of expense spending.
</BodyText>
<br />
<br />
<ButtonLink href="#">Learn more</ButtonLink>
</div>
</div>
To add interactivity to components that are usually static, such as avatars, use the ButtonCompound component.<ButtonCompound shape="circular" onClick={handleClick}>
<Avatar {...avatarProps} />
</ButtonCompound>
Interactive cards
To make cards clickable, use the InteractiveCard component. It supports nested interactive elements without accessibility violations.AI Mark
Use the aiMark prop to display an AI indicator. aiMark accepts a boolean, or one of:
"mark"
"chat"
"edit"
"form"
"mic"
"search"
The aiMark prop cannot be used together with a before icon (a single icon Svg or icon={{ before: Svg }}).| Button usage | aiMark | icon allowed? |
|---|
With children | true or an AI icon name | Only after: use icon={{ after: Svg }} or omit icon. You cannot use a before icon or a single icon Svg. |
Icon-only (no children) | true or an AI icon name | No. Do not pass icon. Only the AI icon is shown. Always provide aria-label. |
With children:<Button appearance="primary" aiMark>Generate</Button>
<Button appearance="secondary" aiMark icon={{ after: ArrowForward }}>Report</Button>
Icon-only AI:<Button aria-label="AI action" aiMark />
<Button aria-label="AI chat" aiMark="chat" />
If a Button component has any children, it will have a 5rem minimum width. This is not applied in icon-only buttons using the icon prop. In some cases, such as when adding a Badge as a child of a Button component without any text, this can lead to unexpected width changes.Either override the width and minWidth of the Button component, or make the Badge a sibling of the Button inside of a div with relative positioning.// option 1
<Button
aria-label="filters button"
icon={FilterIcon}
style={{ width: '2rem', minWidth: '2rem' }}
>
<Badge aria-label="2 active filters">2</Badge>
</Button>
// option 2
<div style={{ position: 'relative', display: 'inline-block '}}>
<Button aria-label="filters button" icon={FilterIcon} />
<Badge aria-label="2 active filters">2</Badge>
</div>
React Accessibility
<Button icon={Edit} aria-label="Edit" />
Use aria-label or aria-labelledby for a button without any text.Provide only an icon for screen readers to read.For more guidance on button labels and accessibility, see button accessibility best practices.<Button
appearance="primary"
size="medium"
icon={StarIcon}
loading={false}
aiMark={true}
onClick={() => console.log("Clicked")}
>
Click me
</Button>
aiMark
boolean | "mark" | "chat" | "edit" | "form" | "mic" | "search"
default:"false"
Shows an AI indicator. When set with button text, a leading icon (plain Svg or icon.before) is not rendered—the AI icon is used instead. On an icon-only button, icon is not rendered. Use icon={{ after: Svg }} for a trailing icon with text.
appearance
"primary" | "secondary" | "ghost" | "danger" | "danger-secondary"
default:"secondary"
icon
Svg | { before: Svg } | { after: Svg }
The SVGR library imports *.svg files as React components, so icon can
accept either a React component, or an object with before or after key
to specify the placement of the icon.
Setting this to true will put the button into a loading state.
size
"xsmall" | "small" | "medium" | "large"
default:"medium"
<ButtonCompound shape="circular" onClick={handleClick}>
<Avatar name="John Doe" />
</ButtonCompound>
shape
"pill" | "circular" | "rounded"
default:"rounded"
<ButtonLink
href="/page"
appearance="primary"
size="medium"
icon={StarIcon}
loading={false}
disabled={false}
>
Click me
</ButtonLink>
appearance
"primary" | "secondary" | "ghost" | "danger" | "danger-secondary"
default:"secondary"
icon
Svg | { before: Svg } | { after: Svg }
The SVGR library imports *.svg files as React components, so icon can
accept either a React component, or an object with before or after key
to specify the placement of the icon.
Setting this to true will put the button into a loading state.
size
"xsmall" | "small" | "medium" | "large"
default:"medium"
Last modified on April 14, 2026