Breaking changes planned for the next major version of Pluma.

This document outlines all planned breaking changes for the next major version of Pluma. These changes are designed to improve consistency, maintainability, and the overall developer experience.
| Change | Affected | Codemod |
|---|---|---|
| Long-hand size names removed | size prop on Button, ButtonGroup, ProgressBar, SegmentedControl, Select, TextField, Toggle | — |
| Short-hand token names removed | s token | — |
*Primitive → Plain* rename | PopoverPrimitive, ModalPrimitive | — |
| Component removals | ToggleButton, LabelIcon, Label | label-to-badge |
| Badge default element | Badge renders a span instead of a div | — |
| Button variant consolidation | variant prop on Button, ButtonGroup | button-variant-rename |
| Event handler standardization | onChange → onCheckedChange on OptionCard, Radio, Checkbox | — |
| Deprecated props removed | Button.isError, Snackbar.isError, Banner warning variant, Popover.ariaLabel, DataTable sorting APIs, Badge.isOutline, Badge.isEmphasized | — |
| Unsafe section components removed | unsafe_leftSectionComponent / unsafe_rightSectionComponent on TextField and Select | — |
| Legacy compatibility styles removed | unsafe_isLegacy on Button, DatePicker, Link, Select, TextArea, TextField, ToggleButton; unsafe_useLegacy* PlumaProvider flags | — |
| Icon sizing + deprecations | All icon usage | — |
Test helper get removed | PlumaTestHelpers | — |
Codemods are a "—" today for most of these — see the Pluma CLI codemods for what's available. Additional codemods for the remaining migrations are planned; as new ones land, this table will be updated.
Long hand size prop values will be removed in favor of shorter, more consistent alternatives:
medium → mdsmall → smlarge → lgAffected Components:
Button - size propButtonGroup - size propProgressBar - size propSegmentedControl - size propSelect - size propTextField - size propToggle - size propShort hand token names will be removed to improve clarity:
s → sm*Primitive Components to Plain*All components with the *Primitive suffix will be renamed to use the Plain* prefix for better clarity:
PopoverPrimitive → PlainPopoverModalPrimitive → PlainModalThis affects all related subcomponents and utilities as well.
The following components will be removed entirely:
ToggleButton - Remove without replacementLabelIcon - Remove in favor of CoinLabel - Remove in favor of Badge with the color prop. Every Label color is supported by Badge and renders identically; color="outline" becomes color="neutral-outline"Button variants will be consolidated from four to three. The current secondary variant is removed; the remaining variants shift down a tier so the visual styles each variant produces stay continuous:
| Current variant | After the major |
|---|---|
primary | primary (unchanged) |
secondary | removed |
tertiary | secondary (now the default-looking, less-prominent button) |
subtle | tertiary (now the most muted variant) |
A codemod and two intermediate flags are available so consumer apps can complete this migration ahead of the major release without any visual regressions:
unsafe_withSoftDeprecatedSecondaryVariant on PlumaProvider's componentConfig.PlumaButton (or per-button). Every variant="secondary" button then renders with the current tertiary styles — the look the new secondary will have post-major.unsafe_withMigratedButtonVariants flag (also on PlumaProvider or per-button), then run the button-variant-rename codemod. The codemod renames tertiary → secondary and subtle → tertiary across .tsx/.jsx (jscodeshift) and .gts/.gjs/.hbs (Glimmer AST) files. With the flag on, the renamed source renders identically to before — no visual regressions.See the codemod README for the full migration order, running instructions, and limitations.
Several components will migrate to more consistent event handler naming:
Change onChange to onCheckedChange:
OptionCard.onChange → OptionCard.onCheckedChangeRadio.onChange → Radio.onCheckedChangeCheckbox.onChange → Checkbox.onCheckedChangeisError prop (use isDanger instead)isError prop (use variant="error" instead)warning variant (use caution instead)ariaLabel prop (use description instead)isEmphasized prop (use color="accent" instead)isOutline prop (use color="neutral-outline" instead, or color="accent-outline" where it was combined with isEmphasized)TextField.unsafe_leftSectionComponent (use elementBefore instead)TextField.unsafe_rightSectionComponent (use elementAfter instead)Select.unsafe_leftSectionComponent (use elementBefore instead)elementBefore and elementAfter take the same content and render in the same places, so the migration is a rename. In Ember they can additionally be filled with an :elementBefore / :elementAfter named block, which the unsafe_ props never supported.
NumberField and Combobox pass their own controls through unsafe_rightSectionComponent internally. That internal channel needs replacing with a private prop before the props can be removed — it is deliberately kept separate from the public elementAfter slot so a consumer's trailing content and the component's own controls can coexist.
Badge will render a <span> instead of a <div> by default. A badge is text-level UI, and a <span> is valid in phrasing contexts (paragraphs, headings, links, buttons) where a <div> is not — this also matches the element the removed Label component rendered, so Labels migrated into text flow become valid again automatically.
The change is visually inert (Badge forces display: inline-flex either way), but:
HTMLDivElement to HTMLSpanElement (React ref types and the Ember Element signature) — TypeScript will surface every affected site.div need updating.as="div" to retain the previous element where it matters.{ id, desc } object form for sortingonSortingChange prop (use onChange in the sorting object instead)Early in the Pluma rollout, several components shipped an opt-in "legacy" style override so they could visually match their old Fly counterparts while apps migrated incrementally. These overrides will be removed in the next major version — components will only render in their current (default) Pluma styles.
unsafe_isLegacy prop removed from:
ButtonDatePickerLinkSelectTextAreaTextFieldToggleButtonPlumaProvider componentFlags removed:
unsafe_useLegacyButtonunsafe_useLegacyTextFieldunsafe_useLegacyTextAreaunsafe_useLegacySelectunsafe_useLegacyLinkRemove these props and flags from your app; the affected components already render in the target style by default.
Various individual icons have been deprecated and will either be:
get functionWhen using PlumaTestHelpers, developers should not use the get function anymore. Instead they should use extract and find.
For more information, please visit the Test Helpers docs.
To prepare for these changes:
medium, small, large with md, sm, lgs with sm*Primitive to Plain*onChange to onCheckedChange where applicableunsafe_isLegacy props and unsafe_useLegacy* PlumaProvider flags — components already render in the target style by defaultLabelIcon usage to the Coin componentlabel-to-badge codemod to migrate Label usage to Badge with the color prop (color="outline" becomes color="neutral-outline") and replace Badge's isEmphasized/isOutline with their color equivalents; review anything the codemod flagsspan instead of a div — update HTMLDivElement ref types and any div-based selectors, or pass as="div" where the previous element is requiredunsafe_withMigratedButtonVariants on PlumaProvider, then run the button-variant-rename codemod to rename tertiary → secondary and subtle → tertiary in your sourceget with extract or findWe recommend updating these incrementally and testing thoroughly. The old APIs will continue to work until the next major version is released.