Anvil2 ships a set of CSS utility classes for applying design tokens to layout, color, typography, and borders. Use these classes when a component prop or layout utility does not cover your styling need.
Add CSS utilities to your project
Anvil2 component CSS is bundled per component. CSS utility stylesheets are separate imports that you add only when you use utility classes.
Wrap your app in AnvilProvider
AnvilProvider applies the anvil2 class to your app and injects theme tokens. Published utility rules are scoped to elements inside that container.import { AnvilProvider } from "@servicetitan/anvil2";
export function App() {
return (
<AnvilProvider>
{/* Your app */}
</AnvilProvider>
);
}
Import the utility stylesheets
Import the full bundle or only the categories you need:// All utilities (~387 classes)
import "@servicetitan/anvil2/assets/css-utils/a2-utils.css";
// Or import by category for a smaller bundle
import "@servicetitan/anvil2/assets/css-utils/a2-spacing.css";
import "@servicetitan/anvil2/assets/css-utils/a2-color.css";
import "@servicetitan/anvil2/assets/css-utils/a2-border.css";
import "@servicetitan/anvil2/assets/css-utils/a2-font.css";
Apply classes to elements inside AnvilProvider
Add a2-* classes through className on Anvil2 components or plain HTML elements:import { AnvilProvider, Card } from "@servicetitan/anvil2";
import "@servicetitan/anvil2/assets/css-utils/a2-utils.css";
export function Example() {
return (
<AnvilProvider>
<Card className="a2-m-inline-4 a2-bg-default">
Card with inline margin and default background
</Card>
</AnvilProvider>
);
}
Utility classes use CSS custom properties from the Anvil2 theme. AnvilProvider injects the active theme values. Fallback values are included in each rule so limited styling works outside a provider, but light/dark mode requires AnvilProvider.
Scoping
Starting in Anvil2 3.0, every published utility rule is scoped under .anvil2. A class such as a2-m-4 only matches elements inside an anvil2 container.
AnvilProvider adds the anvil2 class automatically. If you cannot use AnvilProvider, add the anvil2 class to an ancestor of the elements that use utility classes.
Portaled content (dialogs, popovers, toasts) also needs the anvil2 scope. AnvilProvider mirrors the class on document.body for this reason. See the 2.0 to 3.0 migration guide for details on CSS utility scoping.
Available stylesheets
| Stylesheet | Import path | Contents |
|---|
a2-utils.css | @servicetitan/anvil2/assets/css-utils/a2-utils.css | All utility classes |
a2-spacing.css | @servicetitan/anvil2/assets/css-utils/a2-spacing.css | Margin and padding |
a2-color.css | @servicetitan/anvil2/assets/css-utils/a2-color.css | Background, text, and border colors |
a2-border.css | @servicetitan/anvil2/assets/css-utils/a2-border.css | Border radius and width |
a2-font.css | @servicetitan/anvil2/assets/css-utils/a2-font.css | Font family, size, and weight |
Legacy stylesheets without the a2- prefix (utils.css, spacing.css, and so on) are deprecated. Use the a2-* class names and stylesheets in new code.
The authoritative class list lives in the anvil2 css-utils source directory.
When to use CSS utilities
Prefer Anvil2 components and their props before reaching for CSS utilities:
| Need | Recommended approach |
|---|
| Flexbox or Grid layout | Flex or Grid |
| Responsive layout on components | Layout props |
| Typography | Text |
| Spacing inside a component tree | Component gap, padding, or margin props where available |
| One-off margin, padding, color, or border | CSS utility classes |
Anvil2 intentionally removed many Anvil1 utility categories (flex, grid, display, position, alignment, height, width, z-index, line height, and white space). Use components or layout props for those cases. See the Anvil to Anvil2 migration guide for the full list of changes.
Class naming conventions
All recommended utility classes use the a2- prefix. Each class maps to a design token through a --a2-* CSS custom property.
Spacing (a2-spacing.css)
Spacing utilities set margin or padding using logical properties for internationalization.
| Pattern | CSS property | Example |
|---|
a2-m-{size} | margin (all sides) | a2-m-4 |
a2-m-{direction}-{size} | margin on one axis or side | a2-m-inline-start-4 |
a2-p-{size} | padding (all sides) | a2-p-half |
a2-p-{direction}-{size} | padding on one axis or side | a2-p-block-start-2 |
Size values: 0, quarter, half, 1 through 14
Directions: inline-start, inline-end, block-start, block-end, inline, block, or omit for all sides
Spacing values use rem units. Token values are documented on the Spacing foundations page.
Colors (a2-color.css)
Color utilities set background-color, color, or border-color from semantic tokens.
| Prefix | CSS property | Example |
|---|
a2-bg-* | background-color | a2-bg-primary-hover |
a2-c-* | color | a2-c-subdued |
a2-border-color-* | border-color | a2-border-color-danger |
a2-bg-status-* | background-color (status) | a2-bg-status-success |
a2-c-status-* | color (status) | a2-c-status-warning |
a2-border-color-status-* | border-color (status) | a2-border-color-status-info |
Semantic roles: default, primary, secondary, danger, success, warning, inverted, disabled, transparent-*
Interactive suffixes: -hover, -active, -faint, -subdued, and combinations such as -subdued-hover
Status values: danger, info, success, warning
On-color text: a2-c-on-primary, a2-c-on-danger, and related variants for text on colored backgrounds
Borders (a2-border.css)
| Prefix | Values |
|---|
a2-border-radius-* | none, small, medium, large, xlarge, circular |
a2-border-width-* | none, default, strong |
a2-border-color-* | default, subdued, strong, primary, danger, success, warning |
Typography (a2-font.css)
| Prefix | CSS property | Values |
|---|
a2-ff-* | font-family | heading, label, paragraph |
a2-fw-* | font-weight | heading, label, paragraph |
a2-fs-* | font-size | {heading|label|paragraph}-{xsmall|small|default|large|xlarge} |
For styled text in product UI, prefer the Text component. Typography utilities are useful for plain HTML or custom markup.
Accessibility
| Class | Purpose |
|---|
sr-only | Visually hides content while keeping it available to screen readers |
sr-only is the only utility class without the a2- prefix. It is included in a2-utils.css.
Troubleshooting
Utility classes have no effect
Check these conditions in order:
- Missing
anvil2 scope — Confirm the element is inside an AnvilProvider or an ancestor with the anvil2 class.
- Missing stylesheet import — Import at least one css-utils stylesheet in your app entry or the module that uses the classes.
- Legacy class names — Replace unprefixed classes (for example
m-4) with a2-* equivalents (a2-m-4).
- Legacy CSS overrides — Some monolith CSS can override Anvil2 utilities. If a class appears in the stylesheet but not in the browser, wrap custom styles in an
@layer application block. See the Anvil2 README for the workaround.
Theme colors look wrong
Verify AnvilProvider wraps the tree that contains the styled elements. Utility classes read --a2-* variables injected by the theme provider.