Anvil2

SKILL.md

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 /beta for 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-label or aria-labelledby to 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, not DialogHeader. 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 *_active and *_inactive instead of *_filled and *_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/anvil2 or /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:


For additional documentation and navigation, see: https://anvil.servicetitan.com/llms.txt

Weekly Installs
3
First Seen
6 days ago
Installed on
amp3
cline3
opencode3
cursor3
kimi-cli3
codex3