bc_ui 0.0.2
bc_ui: ^0.0.2 copied to clipboard
A Flutter design system porting heroui-native 1:1 — 45+ token-driven components, light and dark, on a Material 3 base.

A Flutter design system that ports heroui-native 1:1
Same tokens, same variants, same motion — on a Material 3 base, so the rest of the Material ecosystem keeps working.
API reference · Components · Theming · Example app
Why #
- One token system, 64 semantic color slots. Every color is precomputed from
heroui-native's oklch sources — including each
color-mixderived hover/soft shade — into a light and a dark palette. No component hard-codes a color. - iOS-grade surfaces. Continuous ("squircle") corners via
RoundedSuperellipseBorder, layered surface/overlay shadows, and frosted headers built on realBackdropFilterblur. - The motion is ported, not approximated. Press scale 0.985 with width
compensation, switch thumb spring (mass 2 / stiffness 1600 / damping 120),
tab indicator that tracks your finger, 1500ms shimmer — see
BCMotion. - Material stays available.
BCTheme.light()returns aThemeData, soScaffold,Navigator,showDialogand every Material widget still work. - Inter is bundled. No font setup, no missing-glyph surprises.
- 50+ components, all light/dark aware, all documented in the API reference.
| Light | Dark |
|---|---|
![]() |
![]() |
The screen above is assembled entirely from bc_ui — header, card, buttons,
tabs, list group, chips, bottom nav. Its source is
example/lib/showcase/screens/demo_app_screen.dart.
Install #
flutter pub add bc_ui
or add it by hand:
dependencies:
bc_ui: ^0.0.2
Requires Dart SDK ^3.12.1. No other runtime dependencies.
Setup #
import 'package:bc_ui/bc_ui.dart';
MaterialApp(
theme: BCTheme.light(),
darkTheme: BCTheme.dark(),
themeMode: ThemeMode.system,
// Only needed if you use BCToast:
builder: (context, child) => BCToastProvider(child: child!),
home: const HomeScreen(),
);
That's the whole setup — every component reads its colors from the
BCThemeExtension those two factories install.
Quick start #
// Buttons: 7 variants x 3 sizes
BCButton(
variant: BCButtonVariant.secondary,
onPressed: () {},
startContent: const Icon(Icons.add, size: 18),
child: const Text('Add item'),
);
// A frosted app header — pair with extendBodyBehindAppBar so there is
// something to blur. The hairline appears only once content scrolls under.
Scaffold(
extendBodyBehindAppBar: true,
appBar: BCAppHeader(
title: const Text('Inbox'),
subtitle: const Text('12 unread'),
actions: [
BCHeaderIconButton(icon: const Icon(Icons.search), onPressed: () {}),
],
),
body: ListView(children: const []),
);
// Swipeable tabs: the bar and the panels share one controller, so a drag
// switches tabs and carries the indicator with it.
final tabs = BCTabsController<String>(values: const ['music', 'podcasts']);
Column(
children: [
BCTabs(items: items, controller: tabs, fullWidth: true),
Expanded(
child: BCTabView(
controller: tabs,
children: const [MusicPanel(), PodcastsPanel()],
),
),
],
);
// Compound form field with built-in validation states
BCTextField(
isRequired: true,
children: [
const BCTextFieldLabel('Email'),
const BCTextFieldInput(hintText: 'you@example.com'),
const BCTextFieldDescription("We'll never share your email."),
],
);
// Toast
BCToast.show(context, const BCToastData(
title: 'Changes saved',
variant: BCToastVariant.success,
));
Components #
Full props, defaults and enums for every entry: API reference.
| Category | Components |
|---|---|
| Navigation | BCAppHeader · BCSliverAppHeader · BCHeaderIconButton · BCBottomNav · BCNavRail · BCNavDrawer · BCToolbar · BCTabs · BCTabView |
| Actions | BCButton · BCSocialAuthButton · BCBrandLogo · BCLinkButton · BCCloseButton · BCFab · BCSpeedDial · BCToggleButton · BCToggleButtonGroup · BCPressable |
| Containers | BCSurface · BCCard · BCListGroup · BCFlipCard · BCScrollShadow |
| Data display | BCText · BCAvatar · BCChip · BCRibbon · BCTagGroup · BCSeparator · BCSkeleton · BCSpinner · BCProgress · BCLoadingOverlay · BCRating · BCEmptyState |
| Forms | BCInput · BCTextField · BCTextArea · BCPasswordInput · BCSearchField · BCInputOTP · BCDateField · BCTimeField · BCDateTimePicker · BCSelect · BCControlField |
| Selection | BCCheckbox · BCRadioGroup · BCSwitch · BCSlider · BCRangeSlider |
| Overlays | BCDialog · BCPopover · BCMenu · BCToast |
The three pickers — BCDateField, BCTimeField, BCDateTimePicker — share a
presentation prop (dialog, popover, bottomSheet), so swapping one for
another never changes how it opens.
Naming is predictable across the library: variant picks the look, size
picks the metrics, state is controlled (value + onValueChange), and
disabled/invalid are always isDisabled / isInvalid.
Theming #
Custom accent #
BCTheme.light(
overrides: BCThemeOverrides(accent: const Color(0xFF0F766E)),
);
Accent-derived tokens (hover, soft, soft-foreground, focus) are recomputed for you, so a single color change stays consistent everywhere.
Reading tokens in your own widgets #
final bc = context.bcTheme;
DecoratedBox(
decoration: ShapeDecoration(
color: bc.accentSoft,
shape: BCShapes.continuous(BCRadius.xxl),
shadows: bc.surfaceShadow.shadows,
),
);
Design tokens #
BCColorsLight/BCColorsDark (raw palettes) · BCRadius (2→32, field 14) ·
BCSpacing (4px unit) · BCTypography (tailwind text scale) · BCShadows
(layered surface/overlay shadows) · BCMotion (springs and timings) ·
BCShapes (continuous corners) · BCSizes · BCDuration · BCBreakpoints.
See Theme and tokens for the full list.
Example app #
example/ mirrors heroui-native's demo: a full demo screen plus one page per
component, each with vertically paged usage variants and a pagination rail.
cd example && flutter run
Documentation #
- API reference — every component, prop, default and enum. The prop tables are generated from the source, so they track the code.
dart docgenerates the full dartdoc site from the inline documentation.
Tests #
flutter test
License #
The LICENSE file is still a placeholder — pick a license before publishing.

