JustUI is a high-performance, premium Flutter UI component library designed around the copy-paste model (heavily inspired by shadcn/ui).
Instead of adding a bloated third-party package to your project, you use the CLI tool to copy the source code of specific components directly into your own codebase. You own the code, the styling, and the performance characteristics.
- Zero-Dependency Footprint: Built entirely using native Flutter widgets and layout APIs. No external pubspec.yaml dependencies (except Flutter itself).
-
Aspect-Based Rebuilds (
InheritedModel): Rather than rebuilding whole widget trees when a theme changes, JustUI utilizes aspect-based rebuilds so only widgets depending on the specific modified aspect (colors, spacing, or typography) are re-rendered. -
Lazy-Cached Material ThemeData: Compiles custom themes into Flutter's
ThemeDatalazily and caches the instance, saving significant rendering overhead. -
Dynamic Seed Seeding & Contrast Enforcement: Instantiates a custom theme scale from a single seed color and automatically audits/adjusts active elements at runtime.
-
Global Contrast Audit: Automatically enforces WCAG AA accessibility compliance (contrast ratio
$\ge$ 4.5:1 forsuccess,error, andinfo, and$\ge$ 3.0:1 forwarningand focused borders) against generated background colors by adjusting lightness values.
-
Global Contrast Audit: Automatically enforces WCAG AA accessibility compliance (contrast ratio
- Dynamic Brand-Tinted Dark Mode: Generates accessible, premium dark-mode surfaces (background L=3%, card L=7%, elevated L=12%, overlay L=2%) with brand-based hues and clamped saturations for rich aesthetics.
- Ambient Tinted Shadows: Employs a dual-layer shadow system, combining a crisp key shadow (black with low opacity) with a soft ambient shadow (brand-tinted at low opacity).
-
Fluid Spacing & Responsive Corner Radii: Scales spacing and radius properties dynamically from 75% on mobile (viewport width
$\le$ 640px) to 100% on desktop (viewport width$\ge$ 1024px) for optimized responsive layouts. - Interactive CLI Toolchain: A fully offline, interactive CLI for project initialization, component scaffolding, conflict resolution, local change diffing, and dynamic updates.
justui/
├── packages/
│ ├── just_ui_tokens/ # Visual design system primitives (colors, spacing, typography, etc.)
│ ├── just_ui_core/ # Theming engine, lazy caches, InheritedModel, & seed generator
│ └── just_ui_cli/ # Command-Line Interface (scaffolding & copy-paste workflow)
├── registry/ # Raw registry components and files (the copy-paste catalog)
└── docs/ # Phase specifications and design rules
Navigate to packages/just_ui_cli and activate it globally or compile it:
cd packages/just_ui_cli
dart pub global activate --source path .From the root directory of your Flutter application, run:
justui initThe initialization wizard will interactively prompt you for:
- Components target directory (default:
lib/ui) - Tokens target directory (default:
lib/tokens) - Primary brand HEX color (e.g.,
#3b82f6)
It generates a justui.config.yaml and bootstraps a brand-seeded theme configuration at lib/theme/just_theme.dart:
# justui.config.yaml
components_dir: lib/ui
tokens_dir: lib/tokens
registry_url: https://raw.githubusercontent.com/username/justui/main/registryTo view all categorized components available in the remote registry:
justui listTo copy a component and all of its required local dependencies recursively, run:
justui add buttonIf you run the command without arguments, an interactive multi-selection prompt is displayed:
justui addDuring copy-pasting, the CLI automatically:
- Checks for circular dependencies and copies component files into your directories.
- Verifies file integrity using SHA-256 checksums.
- Triggers the Three-Way Conflict Resolution Overwrite Guard if local modifications are detected. You can choose to:
[o] Overwrite(replace local changes with registry updates)[s] Skip(preserve your local modifications)[d] Show Diff(visualize green/red additions and deletions on the terminal)
- Edits your local
pubspec.yamlto append any third-party dependencies required (e.g.flutter_animate) belowdependencies:(making a backup file atpubspec.yaml.bak).
To compare your local copy-pasted files against the original registry versions:
justui diff buttonFor a line-by-line file difference visual output, run:
justui diff button --verboseTo check which of your installed components differ from the registry version and dynamically update them:
justui updateThe CLI will scan your installed components, show a list of outdated ones, and let you interactively select and update them using the Overwrite Guard.
To scaffold a new custom UI component following JustUI's layout and styling guidelines:
justui create my_componentThis creates a standard 4-file bundle under your components directory:
my_component.dart: Widget implementation utilizing aspect-based listeners (context.justColors,context.justSpacing, etc.).my_component_style.dart: Style configuration class for per-instance overrides.my_component_variants.dart: Enums for sizes and variants.my_component_theme.dart: A FlutterThemeExtensionmapping class for global styling overrides.
To preserve 60/120fps rendering speeds, always query design tokens using the specific aspect-based extension methods on BuildContext:
Always fetch specific aspects to ensure widgets only rebuild when that exact property changes:
@override
Widget build(BuildContext context) {
// Good: Rebuilds ONLY when color tokens change
final colors = context.justColors;
// Good: Rebuilds ONLY when spacing tokens change
final spacing = context.justSpacing;
return Container(
padding: .symmetric(horizontal: spacing.md), // Using dot shorthand
color: colors.background,
child: Text(
'JustUI Card',
style: context.justTypo.bodyMd, // Rebuilds ONLY on typo changes
),
);
}Avoid registering rebuild listeners inside event callbacks where rendering state updates are unnecessary. Use readTheme() instead:
ElevatedButton(
onPressed: () {
// Good: Fetches color statically without registering listener to context
final colors = context.readTheme().colors;
print("Primary theme color is: ${colors.primary}");
},
child: const Text("Tap Me"),
)JustUI utilizes Flutter's native ThemeExtension mechanism for per-component style overrides (e.g., JustButtonTheme customizes button styles globally).
Because of this, a Theme widget must be present at the root of the widget tree (which is automatically set up by MaterialApp, or can be provided manually under a WidgetsApp or CupertinoApp by wrapping the tree in a Theme widget with the generated JustThemeData.toThemeData()):
// Example using MaterialApp (automatically sets up Theme)
MaterialApp(
theme: JustThemeData.light.toThemeData(),
darkTheme: JustThemeData.dark.toThemeData(),
home: const MyHomeScreen(),
)
// Example using CupertinoApp / WidgetsApp (requires manual Theme wrapping)
CupertinoApp(
builder: (context, child) {
return Theme(
data: JustThemeData.light.toThemeData(),
child: child!,
);
},
home: const MyHomeScreen(),
)While the components themselves are strictly zero-Material (they do not render Material design components like ElevatedButton or TextField internally, using core Flutter primitives instead), they still rely on the standard Flutter Theme/ThemeData framework for component style overrides.
Please refer to the CONTRIBUTING.md guide for setup instructions, code-style rules (including the Dart Dot Shorthand convention), and registry index formatting.