Anvil2
Anvil2 Skill
Product summary
Anvil2 is ServiceTitan's React-based design system and component library for building consistent, accessible web interfaces. Install via npm install --save @servicetitan/anvil2. Components are imported from @servicetitan/anvil2 (stable) or @servicetitan/anvil2/beta (experimental). The library includes 70+ UI components, layout utilities, hooks, accessibility features, and extended libraries like Atlas for chat interfaces. React 18+ and Node 22+ are required. Primary documentation: https://anvil.servicetitan.com
When to use
Reach for Anvil2 when:
- Building React components for ServiceTitan products or web applications
- Implementing forms, data tables, dialogs, or other standard UI patterns
- Needing accessible, keyboard-navigable interfaces with ARIA support
- Styling components using design tokens instead of custom CSS
- Building chat or AI-powered interfaces (use Atlas extended library)
- Migrating from Anvil 1.0 or older design systems
- Working with responsive layouts that adapt to screen size and device type
- Implementing dark mode or theme switching
Do not use Anvil2 for: custom design systems, Tailwind CSS projects, or non-React applications.
Quick reference
Installation & imports
npm install --save @servicetitan/anvil2
npm install @servicetitan/ext-atlas # for chat components
Common imports
// Core components
import { Button, TextField, Dialog, DataTable, Toast } from "@servicetitan/anvil2";
// Layout utilities
import { Flex, Grid, Layout } from "@servicetitan/anvil2";
// Hooks
import { useBreakpoint, usePrefersColorScheme, useAdaptiveView } from "@servicetitan/anvil2";
// Beta features (experimental)
import { MultiSelectField, DataTable } from "@servicetitan/anvil2/beta";
// Extended library for chat
import { ChatWindow, UserMessage, MarkdownMessage } from "@servicetitan/ext-atlas";
Component structure (compound components)
Anvil2 uses dot notation for sub-components:
<Dialog open={isOpen} onClose={() => setIsOpen(false)}>
<Dialog.Header>Title</Dialog.Header>
<Dialog.Content>Body content</Dialog.Content>
<Dialog.Footer>
<Dialog.CancelButton>Cancel</Dialog.CancelButton>
<Button appearance="primary">Confirm</Button>
</Dialog.Footer>
</Dialog>
Key component categories
| Category | Examples | Use case |
|---|---|---|
| Forms | TextField, TextArea, Checkbox, Radio, Select, DateField | User input and data entry |
| Data display | DataTable, ListView, Pagination | Showing structured or list data |
| Feedback | Toast, Alert, Spinner, FieldMessage | User notifications and status |
| Overlays | Dialog, Drawer, Popover, Tooltip | Modal interactions and hints |
| Layout | Flex, Grid, Layout, Page | Spacing and responsive structure |
| Navigation | Breadcrumbs, SideNav, Tab, Menu | Page structure and routing |
| Chat | ChatWindow, UserMessage, MarkdownMessage (Atlas) | Conversational interfaces |
Design tokens (use instead of hardcoding)
// Colors, spacing, typography are available as CSS variables
<div style={{
color: "var(--color-text-primary)",
padding: "var(--size-4)",
fontSize: "var(--font-size-body-medium)"
}}>
Content
</div>
Responsive breakpoints
// Use responsive layout props on Flex, Grid, Button, etc.
<Button
alignSelf="center"
md={{ alignSelf: "flex-end" }} // 768px and up
xxl={{ alignSelf: "center" }} // 1536px and up
/>
Breakpoints: sm (640px), md (768px), lg (1024px), xl (1280px), xxl (1536px)
Decision guidance
| Scenario | Use | Why |
|---|---|---|
| Simple list vs. complex data | ListView | DataTable |
| Alert vs. Toast | Alert | Toast |
| Dialog vs. Drawer | Dialog | Drawer |
| Controlled vs. uncontrolled form | Controlled (useState) | Uncontrolled (form ref) |
| Beta vs. stable | Stable | Beta |
| Custom styling | Design tokens | Inline styles |
Workflow
1. Set up a component
- Import from
@servicetitan/anvil2(or/betafor experimental) - Check the component's design page for visual guidance
- Review the code page for API and examples
2. Implement with state management
import { useState } from "react";
import { TextField, Button, Flex } from "@servicetitan/anvil2";
function MyForm() {
const [value, setValue] = useState("");
const [error, setError] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
if (!value) {
setError("This field is required");
return;
}
// Submit logic
};
return (
<form onSubmit={handleSubmit}>
<Flex direction="column" gap="4">
<TextField
label="Name"
value={value}
onChange={(e) => setValue(e.target.value)}
error={error}
/>
<Button type="submit" appearance="primary">Submit</Button>
</Flex>
</form>
);
}
3. Add accessibility
- Use semantic HTML (Dialog, Form, etc. handle this)
- Add
aria-labeloraria-labelledbyto custom elements - Test with keyboard navigation and screen readers
- Use FieldLabel and FieldMessage for form context
4. Handle responsive design
- Use Flex/Grid for layout, not custom CSS
- Apply responsive props for breakpoint-specific changes
- Test with useBreakpoint or useAdaptiveView hooks
5. Verify and test
- Check component renders without console errors
- Test keyboard navigation (Tab, Enter, Escape)
- Verify form validation and error messages
- Test on mobile and desktop viewports
- Confirm accessibility with screen reader
Common gotchas
- Don't hardcode colors or spacing: Use design tokens (CSS variables) instead. Never use Tailwind, shadcn/ui, or Material UI.
- Beta components may break: Beta features are marked with a callout. APIs may change; check changelog before upgrading.
- Compound components use dot notation:
Dialog.Header, notDialogHeader. Old PascalCase exports are removed in v2.0. - Required props changed in v2.0: Some previously optional props are now required. Check migration guide if upgrading.
- Form state management: TextField doesn't auto-manage state; use useState or form refs. Controlled components require onChange handlers.
- DataTable pagination is 0-based: pageIndex starts at 0, not 1. Use totalRowCount for server-side pagination.
- Icon filenames changed: Icons use
*_activeand*_inactiveinstead of*_filledand*_outline. - Overlay components need HTML Popover support: No fallback for older browsers; test in target environments.
- Toast requires a provider: Toast.Provider must wrap your app (usually already done in ServiceTitan projects).
- Theming is automatic: usePrefersColorScheme detects system dark mode; no manual theme switching needed unless custom.
Verification checklist
Before submitting work:
- All imports are from
@servicetitan/anvil2or/beta, not other design systems - No hardcoded colors, spacing, or typography values
- Form fields have labels and error messages
- Keyboard navigation works (Tab, Enter, Escape, Arrow keys)
- Component renders without console errors or warnings
- Responsive layout tested on sm, md, lg breakpoints
- Accessibility tested: screen reader announces labels, buttons, and status
- Beta features documented with version and migration plan if used
- No custom CSS or Tailwind classes
- Data tables have pagination configured for large datasets
- Toast/Alert messages are clear and actionable
Resources
Comprehensive navigation: https://anvil.servicetitan.com/llms.txt
Critical documentation pages:
- Getting Started — Installation, prerequisites, setup
- Components Index — Browse all 70+ components
- Patterns — Forms, notifications, errors, filters, empty states
- Migration Guides — Upgrading from Anvil 1.0
- Accessibility — ARIA, semantic markup, labels
- Foundations — Colors, typography, spacing, theming
- Atlas Extended Library — Chat and AI components
- Blog: Understanding Beta Features — When to use experimental components
For additional documentation and navigation, see: https://anvil.servicetitan.com/llms.txt