Skip to content
buttery

v1.0.0

Source on GitHub

Version 1.0.0

Theming

Light and dark, compact density, and your own accent, grays and corners with createTheme.

A theme is what ButteryProvider applies to everything inside it: a color scheme, a density, a motion preference and, optionally, your own accent, grays and corners from createTheme. Use these settings, rather than overriding tokens one by one, so every component changes together.

Light and dark

colorScheme is "system" by default, which follows the operating system, or "light" or "dark" to fix it. Every color token has a value for each, so components need nothing extra.

tsx

import type { ReactElement } from "react";
import { ButteryProvider } from "@butteryui/react";
import { App } from "./App.tsx";

export function Root(): ReactElement {
  return (
    <ButteryProvider colorScheme="system">
      <App />
    </ButteryProvider>
  );
}

Part of a page. A ButteryProvider inside another one sets the scheme for its part of the page only, which is how Elevation shows light and dark surfaces side by side.

Density

density="compact" shortens every control, from 34px fields to 30px and 48px calls to action to 40px, for screens that show a lot at once. The spacing scale stays the same.

Motion

reducedMotion is "user" by default, which follows the operating system's setting. "always" turns motion down for everyone, and "never" keeps it on. Every motion preset reads this setting, as the Motion pages explain.

Reading the settings in code

useButtery() returns what the nearest ButteryProvider resolved:

FieldValue
colorScheme"light" or "dark", with "system" already settled
density"comfortable" or "compact"
platform"web", or "desktop" in a Tauri window
reducedMotionA boolean, true when motion is reduced

tsx

import type { ReactElement } from "react";
import { Text } from "@butteryui/core";
import { useButtery } from "@butteryui/react";

export function SchemeNote(): ReactElement {
  const { colorScheme } = useButtery();
  return <Text variant="caption">Showing the {colorScheme} theme</Text>;
}

Without a provider. useButtery() throws when there's no ButteryProvider above it. A component that has to work with or without one reads ButteryContext with use(ButteryContext) instead, which gives null outside a provider.

Your own theme

createTheme makes a theme from a few choices and returns only the variables that differ from buttery's defaults. Pass it to ButteryProvider's theme:

tsx

import type { ReactElement } from "react";
import { createTheme } from "@butteryui/core";
import { ButteryProvider } from "@butteryui/react";
import { App } from "./App.tsx";

const theme = createTheme({
  accent: "#0f8f7a",
  neutral: "warm",
  radius: "soft",
});

export function Root(): ReactElement {
  return (
    <ButteryProvider theme={theme}>
      <App />
    </ButteryProvider>
  );
}

Each choice is optional:

OptionWhat it setsDefault
accentThe focus ring, selection and links, as hexbuttery's blue
primaryThe main button's color, as hexNear-black, inverted in dark
neutralThe tint of every gray: "gray", "warm" or "cool""gray"
radiusRounder or tighter corners: "soft", "default" or "crisp""default"
densityThe density the provider starts in"comfortable"
overridesThe final word on any color token, per scheme, under light and darkNone

From an accent, buttery works out the shades for light and dark, and an accent-text that meets contrast. At every radius, nested surfaces stay concentric.

  • Colors

    The color tokens every component draws with, by role, in light and dark.

  • Elevation

    Surface levels, from the app's background to dialogs, and the shadows that set them apart.