Frontile v0.18 is a major release that includes several breaking changes aimed at improving the design system's consistency, accessibility, and developer experience. This guide provides an overview of all breaking changes and links to detailed migration guides for each.
Two of these changes stop your app from working. The rest are cleanup, and one of them is optional for the whole 0.18 line.
| Change | If you skip it | Fails how? |
|---|---|---|
Missing @import "@frontile/theme" |
No Frontile styles at all | Loudly — the app is visibly unstyled |
Numbered color classes (bg-primary-500) |
Those elements render unstyled | Silently |
bg-background → bg-surface-canvas |
Those elements render unstyled | Silently |
--frontile-* variable references |
The declaration is dropped | Silently |
Nested LayoutTheme config |
Build or type error | Loudly, and only if you customize the theme |
@frontile/* package imports |
Nothing — they still work in 0.18.x | Deprecation warning only |
| Derived border-radius scale | Slightly rounder corners on menus and small marks | Visual only — nothing to fix |
| Multi-select renders chips | Multi-selects look different — selections become removable chips | Visual only — nothing to fix |
The silent ones are the reason to take this in order. A class Tailwind can't
resolve produces no error, no warning, and no CSS — the element just renders
without the style you asked for. We hit this in Frontile's own documentation
during the 0.18 work: thirteen demos were shipping with bg-success-50 and
bg-warning-50, rendering with no background at all, and nobody noticed until a
linter went looking. Budget time for looking at the result, not just for the
find-and-replace.
Nothing else is verifiable until the theme loads. Add the CSS import, and update your config shape if you customize it.
Impact: required. Time: 15–30 minutes.
@import "@frontile/theme" to your app/styles/app.cssLayoutTheme moved from a flat to a nested structure (hoverOpacity becomes
opacity: { hover })--frontile- prefix; colors gained --color-See: Theme Configuration
One pass over your classes and custom CSS. Everything in this step fails silently, so verify visually as you go rather than at the end.
Impact: required, and touches every colored element. Time: an hour or two for a small app, a day or more for a large one.
50, 100, … 950) become named levels (subtle, muted,
soft, mild, DEFAULT, firm, strong, bolder)default-* becomes neutral-*bg-background becomes bg-surface-canvas{color}-foreground and contrast-1/contrast-2 become on-{color}-{level}text-foreground is gonetheme-inverse flips every semantic token in a region, for panels that should read as the opposite themeColors also moved from HSL to OKLCH. That part is automatic — you may notice small perceptual differences, but there is nothing to change.
See: Semantic Colors
Seven @frontile/* component packages became the single frontile package. The
old packages still re-export everything and only log a deprecation warning, so
your imports keep working for all of 0.18.x.
Leave this until the app builds and looks right. It rewrites every Frontile import in your codebase, and doing that first buries the changes above in a diff you can't read — which matters precisely because those changes fail silently.
Impact: none until 0.19. Time: 10–30 minutes, mostly automated.
Select with @selectionMode="multiple" used to show its selections as a
comma-joined string inside the trigger. It now renders each selection as a
removable Chip, so users can drop one
selection without reopening the dropdown. The control grows taller as chips
wrap, and a chips field is deliberately the same height as a same-size single
select (46px at md).
Nothing breaks, but the field is taller and looks different. If a layout depends on the old fixed-height appearance, opt back out per-select:
<Select @selectionMode='multiple' @selectedItemsDisplay='text' />
Chips inherit the Select's @intent and default to the faded appearance;
@chip={{hash appearance='outlined' size='md'}} tunes appearance, intent,
size, radius and withDot. @allowEmpty defaults to false, so the final
selection's chip renders with no close button; @isClearable clears
everything and ignores @allowEmpty. Chip close buttons are deliberately not
in the tab order — the combobox is the single tab stop, and Backspace on
the field removes the last chip in both filterable and non-filterable modes.
See the Select docs
for the full section.
Impact: visual only. Time: none required; a few minutes if you want to opt out.
@import "@frontile/theme" added to app.cssLayoutTheme config nested, if you customize it--frontile-* variable references renamed (colors take --color-)default-* renamed to neutral-*bg-background replaced with bg-surface-canvas{color}-foreground / contrast-* replaced with on-{color}-{level}frontile (optional until 0.19)Starting fresh on v0.18 needs no migration. Follow Getting Started .