Make an existing app buttery
Bringing buttery into an app that already has its own styles and components, a screen at a time.
This guide moves an existing React app onto buttery without a rewrite: wire up the provider, check the layout, then convert a screen at a time from the top down. Follow it when an app already works and you want it to look, move and lay out like buttery.
Move the app across
Wire it up
npx buttery initbuttery initdoes this step for you, with buttery's lint configs and what coding agents read, andnpx buttery doctorchecks the result. By hand, import buttery's two stylesheets at the app's entry and wrap the app inButteryProvider:import "@butteryui/core/styles.css"; import "@butteryui/react/styles.css"; import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; import { ButteryProvider } from "@butteryui/react"; import { App } from "./App.tsx"; const container = document.getElementById("root"); if (!container) throw new Error("index.html needs a #root element."); createRoot(container).render( <StrictMode> <ButteryProvider colorScheme="light"> <App /> </ButteryProvider> </StrictMode>, );buttery's styles sit in CSS cascade layers, so a style the app sets itself still wins. Whatever the app leaves to the browser changes, through buttery's base styles and a small reset:
Left to the browser With buttery The page's font Inter, with bodytext at 14px on a 20px lineThe page's background and text buttery's colors Box sizing box-sizing: border-boxon every elementHeadings, paragraphs and lists No default margins Images and SVGs Blocks no wider than their container Form controls Their font from the page Selected text buttery's selection color Keyboard focus buttery's focus ring Scrollbars Thin, in the border color Light and dark.
ButteryProviderfollows the system's light or dark setting, which switches those colors. PasscolorScheme="light", as above, until the app's own styles are ready for dark.The app also gains buttery's tokens, the layers that menus, dialogs and toasts open into, and
LayoutGuardin development.See where it stands
Run the app in development and narrow the window from wide to a phone's width.
LayoutGuardoutlines what overlaps, overflows or sits off the spacing scale.Then add a Playwright test for each main page, and keep its report as the list of what to fix:
import { test } from "@playwright/test"; import { expectButtery, quickMatrix } from "@butteryui/test"; test("the home page is buttery", async ({ page }) => { await page.goto("/"); await expectButtery(page, { ...quickMatrix, name: "home" }); });Convert a screen, top down
Take one screen at a time, from the whole screen down to its values:
Level What to do The screen Match it to a pattern if one fits: AppShellwithAppPage, a settings page, a detail pageIts regions Give each a Surfacelevel, and lay out siblings withStack,InlineandGrid, dropping margins for gapsIts controls Swap each for its buttery component: Button,TextField,Select,SwitchAnything without a match Wrap it in buttery(Component, { surface: "card" }), so it takes the surface and motion recipesIts values Replace raw colors, sizes, radii and durations with tokens; buttery's stylelint config lists the ones left Keep it there
Add
@butteryui/lint's configs and theexpectButterytests to the app's checks, so a screen stays buttery once it's converted. Lint configs has both config files.
Related
- Make anything buttery
The four ways to bring buttery into an app, from wiring up the provider to whole-page patterns.
- Check your layout
Catching overlaps, overflow and layout shift while you work and in your tests.