Skip to main content

Migrating from Anvil2 1.x to 2.0

Anvil2 2.0 is a major release that removes all previously deprecated APIs, standardizes component composition, and updates several required props. Because deprecated APIs have been fully removed, upgrading from v1.x will surface build-time errors that must be resolved before your application can compile. This guide walks through the required changes and common migration patterns.
  • Deprecated components and props have been removed and will now throw build errors
  • Several internal sub-exports that were accidentally surfaced are no longer exported; use the existing compound/component namespace API instead
  • Several previously optional props are now required
  • Overlay components no longer have a fallback for browsers without HTML Popover support.
  • Some Icon filenames have been renamed for consistency

Component Behavior Changes

Chip

When using size="small", Chip now allows only one of the following props:
  • onChange
  • onClose
// ❌ Invalid
<Chip size="small" onChange={handleChange} onClose={handleClose} />

// ✅ Valid
<Chip size="small" onChange={handleChange} />

Overlay Components

The following components using the HTML Popover API no longer have a fallback:
  • Tooltip
  • Popover
  • Menu
  • Combobox
No API changes are required, but this change requires that consumers of Anvil2 use a browser that is compatible with the HTML Popover API.

Removed Exports → Compound Component APIs

Several components previously exposed internal sub-exports at the package surface. Those internal exports are now removed from the public surface. Use the existing compound / namespaced APIs instead.

Dialog

// ❌ Removed exports
import {
  DialogContent,
  DialogHeader,
  DialogFooter,
  DialogCancelButton,
} from "@servicetitan/anvil2";

// ✅ Use the compound API
<Dialog>
  <Dialog.Header />
  <Dialog.Content />
  <Dialog.Footer />
  <Dialog.CancelButton />
</Dialog>

SideNav

// ❌ Removed exports
import { SideNavLink, SideNavGroup } from "@servicetitan/anvil2";

// ✅ Use the compound API
<SideNav>
  <SideNav.Group>
    <SideNav.Link />
  </SideNav.Group>
</SideNav>

Other Components Using the Same Pattern

ComponentRemoved Export(s)Replacement API
BreadcrumbsBreadcrumbsElementBreadcrumbs
CheckboxCheckboxGroupCheckbox.Group
DetailsDetailsSummary, DetailsContentDetails.Summary, .Content
PopoverPopoverTrigger, PopoverContent, PopoverClose, PopoverButtonPopover.Trigger, .Content, .Close, .Button
RadioRadioGroupRadio.Group
SelectCardSelectCardElement, SelectCardGroupSelectCard, SelectCard.Group
ToolbarToolbarElement, ToolbarButton, ToolbarSelectToolbar, Toolbar.Button, .Select

Removed Components

DateField

The deprecated DateField component has been removed.
// ✅ Replace with one of:
<DateFieldSingle />
<DateFieldRange />

Removed / Replaced Props

All deprecated props have been removed in 2.0 and will now cause build errors.

Dialog

  • Removed:
    • onOpen
    • onOpenChange
  • Use instead:
    • onOpenAnimationStart
    • onOpenAnimationComplete
    • onClose

Popover

  • Removed:
    • onOpenChange
    • onOutsidePress
    • disableFocusLock
    • root
  • Replacements:
    • onClickOutside
    • modal
// ❌ Removed
<Popover onOutsidePress={handleOutside} disableFocusLock root />

// ✅ Updated
<Popover onClickOutside={handleOutside} modal />
  • Popover.Trigger
    • data-state has been replaced with aria-expanded

Drawer

  • Removed: onOpen
  • Use:
    • onOpenAnimationStart
    • onOpenAnimationComplete

Calendar

// ❌ Removed
unavailableDates

// ✅ New API
unavailable={{ dates: [...] }}

Flex

flexShrink has been replaced by shrink.
// ❌
<Flex flexShrink="1" />

// ✅
<Flex shrink="1" />

Textarea

  • errorAriaLive no longer accepts a boolean
// ❌
errorAriaLive={true}

// ✅
errorAriaLive="assertive" // "polite" | "off"

Toaster

  • Removed:
    • duration
    • forceRender
Toast duration must now be set on individual toasts.

Field-Level openMoreInfo

Removed from the following components:
  • FieldLabel
  • Combobox.Trigger
  • SelectTrigger
  • Textarea
// ❌
openMoreInfo

// ✅
moreInfoOpen

// ❌
<Link quiet />

// ✅
<Link ghost />

Newly Required Props

The following props are now required and must be provided to avoid build errors:
ComponentRequired Prop
RadioGrouplegend
Toolbar.ButtononClick

Icon Renames

Several icons were renamed for consistency. Update any imports or asset references accordingly:
Old NameNew Name
gnav_dial_pad_filled.svggnav_dial_pad_active.svg
gnav_dial_pad_inactive_outlinegnav_dial_pad_disabled.svg
gnav_dial_pad_outline.svggnav_dial_pad_inactive.svg
gnav_home_filled.svggnav_home_active.svg
gnav_home_outline.svggnav_home_inactive.svg
gnav_legacy_search_filled.svggnav_legacy_search_active.svg
gnav_legacy_search_outline.svggnav_legacy_search_inactive.svg

Optional: Anvil2 v2 Migration Claude Skill

To help teams prepare for the Anvil2 v2 migration, an optional Claude skill is available that scans the codebase for deprecated Anvil2 patterns and applies safe, mechanical fixes where possible.
Thanks to Kiryl Chetyrbak for creating and sharing this Claude skill.
Script location:
https://github.com/servicetitan/ai-codegen-tools/blob/master/plugins/skills/preparing-anvil2-migration/SKILL.md

What the script does

The script performs a structured migration pass with the following workflow:
  1. Scans the codebase for known Anvil2 v2 deprecations
  2. Applies automatic fixes for clear, unambiguous replacements
  3. Flags items that require manual decisions or review, including file locations
  4. Produces a summary of changes made and remaining action items

Types of changes it handles

The script covers a broad set of Anvil2 v2 migration rules, including:
  • Renamed exports and components
    • e.g. BreadcrumbsElement → Breadcrumbs
  • Pascal-case subcomponents migrated to dot notation
    • e.g. DialogContent → Dialog.Content
  • Icon naming changes
    • e.g. *_filled → *_active
  • Prop renames and removals
    • e.g. quiet → ghost, removed Menu.open
  • Event handler changes
    • e.g. onOpen → onOpenAnimationStart / End
  • Component replacements
    • e.g. DateField → DateFieldSingle / DateFieldRange
  • Import path updates
    • e.g. TooltipContext moved to @servicetitan/anvil2/base
  • Context-based fixes
    • Infers missing RadioGroup legends
    • Chooses DateFieldSingle vs DateFieldRange based on usage

Decisions that require manual input

Some migrations cannot be resolved automatically. In these cases, the script will stop and ask for guidance, for example:
  • Chip size="small" with both onClick and onClose
  • Toolbar.Button without an onClick handler

What this script does not do

  • It does not guarantee full Anvil2 v2 compatibility
  • It does not replace manual review or testing
  • It should not be treated as a one-click migration

When to use it

We recommend running this script early in the migration process to:
  • Reduce manual discovery of deprecated patterns
  • Apply consistent, mechanical fixes automatically
  • Surface migration decisions before deeper refactors begin
This script is a convenience tool, not a required or officially supported migration step. Teams remain responsible for validating behavior, accessibility, and visual correctness after migration.
Last modified on March 13, 2026