@byearlybird/budgie
v0.2.0
Published
Reusable React components from By Early Bird.
Maintainers
Readme
@byearlybird/budgie
Reusable React components by Early Bird, built with TypeScript and CSS Modules.
[!WARNING] Status: Alpha. Budgie is under active development. Component APIs, styling, and design tokens may change before 1.0.
Install
pnpm add @byearlybird/budgieBudgie supports React 19.2 and later React 19 releases. If the consuming app does not already have React installed, add it too:
pnpm add react react-domKarla is Budgie's preferred font. Font files are not bundled with the component library, so install them in the consuming application:
pnpm add @fontsource-variable/karlaUse
import "@fontsource-variable/karla";
import {
BarChart,
Button,
ButtonIcon,
Checkbox,
Combobox,
ComboboxClear,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxInputGroup,
ComboboxItem,
ComboboxLeadingIcon,
ComboboxList,
ComboboxTrigger,
Input,
InputAction,
InputGroup,
InputIcon,
LineChart,
Menu,
MenuContent,
MenuItem,
MenuTrigger,
PieChart,
Radio,
RadioGroup,
Select,
SelectContent,
SelectItem,
SelectLeadingIcon,
SelectList,
SelectTrigger,
SelectValue,
Switch,
Textarea,
} from "@byearlybird/budgie";
import "@byearlybird/budgie/style.css";
import { PaletteIcon, SearchIcon } from "./icons";
export function Example() {
return (
<form>
<InputGroup>
<InputIcon>
<SearchIcon />
</InputIcon>
<Input aria-label="Search" placeholder="Search" />
<InputAction type="submit">Search</InputAction>
</InputGroup>
<Button>
<ButtonIcon>
<SearchIcon />
</ButtonIcon>
Find another
</Button>
<Textarea aria-label="Notes" name="notes" placeholder="Add notes" />
<label>
<Checkbox name="updates" />
Send me updates
</label>
<RadioGroup aria-label="Theme preference" defaultValue="system" name="theme-preference">
<label>
<Radio value="system" />
System
</label>
<label>
<Radio value="dark" />
Dark
</label>
</RadioGroup>
<label>
<Switch name="compact" />
Compact mode
</label>
<Menu>
<MenuTrigger>Actions</MenuTrigger>
<MenuContent>
<MenuItem>Duplicate</MenuItem>
<MenuItem>Rename</MenuItem>
</MenuContent>
</Menu>
<Combobox items={fruits} name="fruit">
<ComboboxInputGroup>
<ComboboxLeadingIcon>
<SearchIcon />
</ComboboxLeadingIcon>
<ComboboxInput aria-label="Fruit" placeholder="Search for a fruit" />
<ComboboxClear />
<ComboboxTrigger />
</ComboboxInputGroup>
<ComboboxContent>
<ComboboxEmpty>No fruits found.</ComboboxEmpty>
<ComboboxList>
{(fruit) => (
<ComboboxItem key={fruit.value} value={fruit}>
{fruit.label}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
<Select items={themes} name="theme">
<SelectTrigger aria-label="Theme">
<SelectLeadingIcon>
<PaletteIcon />
</SelectLeadingIcon>
<SelectValue placeholder="Select a theme" />
</SelectTrigger>
<SelectContent alignItemWithTrigger={false}>
<SelectList>
{themes.map((theme) => (
<SelectItem key={theme.value} value={theme.value}>
{theme.label}
</SelectItem>
))}
</SelectList>
</SelectContent>
</Select>
</form>
);
}
const themes = [
{ label: "Light", value: "light" },
{ label: "Dark", value: "dark" },
];
const fruits = [
{ label: "Apple", value: "apple" },
{ label: "Mango", value: "mango" },
];Import @byearlybird/budgie/style.css once in the consuming app's root entry or
layout. The component source uses CSS Modules, and the package exposes the compiled,
scoped stylesheet as this stable CSS entry.
Button, Input, and the Select and Combobox parts extend their
corresponding Base UI primitives, including state-aware className, Field
integration, and ref support. Wrap Input in InputGroup when icons or other
adornments need to sit beside it. SelectLeadingIcon and
ComboboxLeadingIcon provide the same leading-icon composition for selection
controls. Textarea extends the native textarea props.
Overlays
Dialog and Drawer include themed backdrops, surfaces, titles, descriptions, triggers,
and close controls. Their Content components supply the standard portal, backdrop,
viewport, and popup structure. Drawer additionally supports Base UI's swipe
directions, snap points, nested drawers, and virtual keyboard provider.
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogTitle,
DialogTrigger,
Drawer,
DrawerClose,
DrawerContent,
DrawerDescription,
DrawerTitle,
DrawerTrigger,
} from "@byearlybird/budgie";
<Dialog>
<DialogTrigger>Open dialog</DialogTrigger>
<DialogContent>
<DialogTitle>Edit profile</DialogTitle>
<DialogDescription>Update your public profile details.</DialogDescription>
<DialogClose>Close</DialogClose>
</DialogContent>
</Dialog>;
<Drawer swipeDirection="right">
<DrawerTrigger>Open drawer</DrawerTrigger>
<DrawerContent>
<DrawerTitle>Account settings</DrawerTitle>
<DrawerDescription>Update your account details.</DrawerDescription>
<DrawerClose>Close</DrawerClose>
</DrawerContent>
</Drawer>;Layout
Budgie provides Box, Flex, Grid, Container, and Section for token-backed
page and component layouts. Spacing props use the Pollen size token names rather
than raw measurements. px controls the inline (x) axis and py controls the block
(y) axis.
<Section size="2">
<Container size="3" px={{ initial: "4", md: "8" }}>
<Grid columns={{ initial: "1", sm: "2" }} gap="4">
<Box p="4">First</Box>
<Box p="4">Second</Box>
</Grid>
</Container>
</Section>All layout props accept responsive objects keyed by initial, xs, sm, md,
lg, and xl. The spacing values "1", "2", "3", "4", "8", and "10"
resolve to their matching --size-* tokens. CSS variable references are also
accepted when an application provides a semantic token of its own.
Design tokens
Budgie exposes its tokens separately from its component styles. Apps that only need the shared tokens can import the standalone entry:
@import "@byearlybird/budgie/tokens.css";@byearlybird/budgie/style.css already includes these tokens, so apps using Budgie
components should import only the component stylesheet. The standalone token entry
contains Budgie's public theme and layout values and the Pollen primitives used by
the library.
:root {
--budgie-color-primary: #252523;
--budgie-color-primary-text: #faf9f6;
--budgie-color-background: #faf9f6;
--budgie-color-text: #252523;
--budgie-color-border: #b8b5ad;
--budgie-color-muted: #e3e1da;
--budgie-font-family: "Karla Variable", "Karla", ui-sans-serif, system-ui, sans-serif;
--budgie-radius-surface: 2px;
--budgie-radius-input: 9999px;
--budgie-radius-button: 9999px;
--budgie-layout-container-1: 28rem;
--budgie-layout-container-2: 43rem;
--budgie-layout-container-3: 55rem;
--budgie-layout-container-4: 71rem;
}Budgie follows the system color-scheme preference by default. Set data-theme on
the document root or any containing element to select a mode explicitly:
<html data-theme="dark">
<!-- Budgie components use the dark theme -->
</html>Both data-theme="light" and data-theme="dark" can be scoped to part of a page.
The light defaults use a warm off-white surface with softened neutral borders. The
dark defaults use a deep charcoal surface, warm light text, and quieter dark
borders. Surfaces use a crisp 2px radius, while form inputs and buttons use fully
rounded shapes.
Override any of these values after the Budgie stylesheet:
@import "@byearlybird/budgie/style.css";
:root {
--budgie-color-primary: #1d4ed8;
--budgie-color-primary-text: #fff;
--budgie-font-family: "Avenir Next", ui-sans-serif, system-ui, sans-serif;
--budgie-radius-surface: 12px;
--budgie-radius-input: 6px;
--budgie-radius-button: 9999px;
}If Karla is not installed or loaded, the token falls back to the application's
system sans-serif font. Budgie supplies consistent hover and focus behavior. Its
defaults use :where(:root), so applications can override them without specificity
tricks.
Charts
Budgie includes opinionated line, bar, and pie charts powered by Recharts. Each chart is responsive, supports light and dark themes, and uses the existing Budgie color tokens by default.
const data = [
{ month: "Jan", current: 42, previous: 32 },
{ month: "Feb", current: 48, previous: 38 },
{ month: "Mar", current: 45, previous: 41 },
];
<LineChart
data={data}
title="Account growth"
description="Monthly active accounts."
xKey="month"
series={[
{ dataKey: "current", label: "This year" },
{ dataKey: "previous", label: "Last year" },
]}
/>;
<BarChart
data={data}
title="Monthly accounts"
xKey="month"
series={[{ dataKey: "current", label: "Accounts" }]}
/>;
<PieChart
data={[
{ plan: "Individual", share: 54 },
{ plan: "Team", share: 29 },
{ plan: "Enterprise", share: 17 },
]}
title="Customer mix"
nameKey="plan"
valueKey="share"
valueFormatter={(value) => `${value}%`}
/>;Set a series color or pass a colors array to PieChart when a product-specific
palette is needed. CSS color values, including application theme variables, are
supported.
Develop
vp install
vp exec playwright install chromium
vp run storybookStorybook runs at http://localhost:6006.
Validate and build
vp check
vp test
vp run build
vp run build-storybookvp test runs the SSR smoke test and all Storybook component tests in headless Chromium.
The package build is written to dist/, and the static Storybook site is written to
storybook-static/.
Publish
Authenticate with npm, choose a new version, then publish:
vp dlx bumpp
pnpm publishThe package is configured for public scoped publishing.
