This guide covers changes to the beta Details component. These APIs may
continue to evolve before the stable release.
Overview
The betaDetails.Summary replaces children with a label string and lays the label and its attribute cells out on a shared grid:
label- The summary text. It supports*italic*and==highlight==markup.labelProps- Sets the label’s textsizeand adds an optionalmoreInfotooltip.attributes- Adds text, chip, button, and menu cells after the label.templateColumns- Defines the grid tracks the label and cells share.gap- Sets the space between those tracks.
Design Rationale
Why label instead of children?
Previously, children accepted any React element, so each summary styled its own content:
Text with the summary’s original typography, so a plain label looks the same as it did with plain-text children.
Why a grid?
The label and the cells are siblings in one grid, so a singletemplateColumns value sets the width of each. The label takes the first track, and each cell takes the next one. Use the same proportions as the content below to keep each cell near its column. The grid sits inside the summary’s padding, so the cells are offset by a few pixels from the content’s own columns.
Label Reference
The label is bold and uses the display font by default. Two inline markers are supported:
Any other marker, including
**bold** and backticks, renders as literal text. The label is already bold, so bold markup is not needed.
Label sizes
UselabelProps.size to change the label’s text scale. The expand arrow scales with the label at 1.5 times its font size.
medium is the default.
More info
SetlabelProps.moreInfo to a string to add an info button right after the label. Hovering or focusing the button shows the string in a tooltip.
labelProps.size. moreInfo takes a string only.
Best practice: use sentence case
Write labels in sentence case: capitalize only the first letter of the first word, plus proper nouns. Sentence case keeps labels easy to scan and matches the rest of Anvil2. The expand arrow aligns to the height of capital letters, so a label that starts with a capital letter sits most evenly beside it.Attributes Reference
attributes takes an array of cells. Each cell has a type and renders after the label in the order given. Cells are aligned to the end of their track and do not wrap.
Text cells
label and value are both optional. The colon appears only when both are set, and an empty string counts as not set. size takes the same values as the label and defaults to medium.
Chip cells
label and color are the Chip props of the same names.
Button cells
A button cell is always a labeled button, so there is no icon-only form.appearance defaults to secondary. A bare icon renders before the label. Use { after: Icon } to place it after.
Menu cells
A menu cell takesitems, each with a label, an optional onClick, and an optional disabled. Selecting an item runs its onClick and closes the menu. Submenus are not supported.
Placing cells on the grid
templateColumns defaults to 1fr, which gives the label the whole row. Add one track for each cell:
gap takes the same values as the Grid component.
Click behavior
The whole summary row toggles the Details. Clicking the label, a text or chip cell, or empty space in the row opens or closes it. Button and menu cells sit beside the toggle button, not inside it. They run only their own action and do not toggle: pressing a button, opening a menu, or choosing a menu item leaves the Details as it is. Keyboard users toggle the Details with the toggle button, and tab to each button or menu cell as a separate control. The toggle button’s accessible name is the label alone.Styling the summary
className and style apply to the summary row, so they style the whole summary: background, padding, border, and radius. Every other prop, including ref, onClick, aria-*, and data-*, goes to the toggle button.
Override the summary’s colors with custom properties on the row, set through style:
style for these properties. A class with a single selector can lose to the component’s own rule.
The focus ring is drawn around the whole row when the toggle button has keyboard focus. To style focus from your own className, use :has([data-anv="details-summary"]:focus-visible) on the row. Avoid :focus-within, which also matches when a button or menu cell in the row has focus.
Migration Guide
Plain text summaries
Summaries with inline emphasis
Summaries with extra elements
Move chips, buttons, and values out ofchildren and into attributes:
Summaries with a different text size
Breaking Changes
The following changes apply to the betaDetails.Summary:
childrenhas been removed - Uselabelinstead.classNameandstylenow apply to the summary row, not the<button>element - A rule that targeted the button itself, such as itsdisplayor:focus-visible, needs to target the row. Overrides that set padding, background, or the--a2-mod-details-summary-*custom properties work unchanged.- The label renders as
Text- Content that relied on custom elements, fonts, or colors inside the summary must move toattributescells or be dropped.
Why Breaking?
The point of the new API is a constrained summary. Acceptingchildren alongside label would keep the arbitrary content the change removes, and beta status allows the API to change.
New Exports
The following are now exported from@servicetitan/anvil2/beta:
Details- The disclosure container, withDetails.SummaryandDetails.Content.DetailsProps- Props forDetails.DetailsSummaryProps- Props forDetails.Summary.DetailsSummaryLabelProps- ThelabelPropsoptions.DetailsSummaryColumnAttribute- An attribute cell.DetailsSummaryTextAttribute- A text cell.DetailsSummaryChipAttribute- A chip cell.DetailsSummaryButtonAttribute- A button cell.DetailsSummaryMenuAttribute- A menu cell.DetailsSummaryMenuItem- An item in a menu cell.DetailsContentProps- Props forDetails.Content.