widgets_box 0.2.0 copy "widgets_box: ^0.2.0" to clipboard
widgets_box: ^0.2.0 copied to clipboard

A Flutter package for efficient UI state management, handling loading, empty views, content display, caching, and pull-to-refresh with customizable widgets.

Widgets Box — a theme-aware Flutter UI framework

widgets_box

One theme-aware component system for every Flutter app you ship.
Screens, cards, fields, buttons, status & app-infrastructure widgets — styled once, consistent everywhere.

pub version pub points pub likes License Repo stars


Why widgets_box? #

Every app re-implements the same building blocks — a loading/empty/content screen, a status pill, a labelled text field, a themed button — and they drift apart. widgets_box is the single source of those blocks:

  • 🎨 Theme-aware — every widget reads your ThemeData first, so it matches your brand with zero configuration.
  • ⚙️ Fully configurable — set package-wide defaults once with WidgetsBoxConfig, override per-instance anywhere.
  • 🧩 20+ widgets — screens, cards, list rows, status badges, detail rows, section headers, inputs, buttons, images, toasts.
  • 🛠️ App infrastructure — a debug-only backend environment switcher, in-process app restart, "Powered by" and app/Shorebird version widgets.
  • 🔤 WB-prefixed API — type WB and autocomplete surfaces the whole library. Old names still work via deprecated aliases.
  • 🌍 Localized — ships English + Arabic strings out of the box via smart_localize.

Widgets Box component gallery


Table of Contents #

Installation #

dependencies:
  widgets_box: ^0.2.0
import 'package:widgets_box/widgets_box.dart';

Optionally wrap your app in a WidgetsBoxConfigProvider (see Styling precedence) to set package-wide defaults. Everything else works straight from your Theme.

Styling precedence #

Every visual value resolves top-down, so an app themes once and overrides only where it needs to. A null at any layer simply falls through to the layer below.

Styling precedence: Flutter Theme → WidgetsBoxConfig → constructor params

Wrap the app in a WidgetsBoxConfigProvider to set package-wide defaults (card radius/padding, field borders, button sizing, toast colors); anything left unset falls back to your Flutter Theme.

WidgetsBoxConfigProvider(
  config: const WidgetsBoxConfig(
    cardConfig: WBCardConfig(radius: 16, padding: EdgeInsets.all(16)),
    buttonConfig: ButtonConfig(radius: 8, height: 44),
  ),
  child: const MyApp(),
);

Screens & state #

WBScreen wires loading, empty and content states together with pull-to-refresh in one place.

WBScreen(
  isLoading: state.isLoading,
  isEmpty: state.items.isEmpty,
  onRefresh: () => controller.reload(),
  emptyWidget: WBEmptyState(
    title: 'No orders yet',
    subtitle: 'Pull to refresh or try again.',
    onRetry: controller.reload, // localized "Retry" (en/ar) by default
  ),
  builder: (context) => OrdersList(items: state.items),
);
const WBLoading();                                 // themed loading indicator
WBEmptyState(subtitle: 'Nothing here').toSliver(); // drop into a CustomScrollView

Cards & content #

WBCard(
  onTap: openInvoice,
  child: Column(
    children: [
      WBSectionHeader(title: 'Invoice #10428', actionLabel: 'View', onAction: openInvoice),
      WBDetailRow(label: 'Supplier', value: 'Nile Vet Supplies'),
      WBDetailRow.money(label: 'Total', value: 12500, total: true),
    ],
  ),
);

// Image-led card
WBCard.media(
  image: WBCachedImage(imageUrl: product.image),
  child: Text(product.name),
);

Status & tags #

WBStatusBadge resolves its color from an explicit color, a hex string (#2E7D4F), or a semantic name (success, danger, warning, info, primary, gray).

WBStatusBadge(label: 'Active',  colorValue: 'success');
WBStatusBadge(label: 'Overdue', colorValue: 'danger', icon: Icons.warning);
WBStatusBadge(label: 'Draft',   colorValue: '#2563EB', outlined: true);

WBTag(text: 'New', backgroundColor: Colors.blue, textColor: Colors.white);

Inputs #

WBTextField ships with typed factories that pre-wire keyboard, validation and affordances.

WBTextField(title: 'Username', hintText: 'Enter username', controller: nameCtrl);

WBTextField.email(title: 'Email', controller: emailCtrl);
WBTextField.password(title: 'Password', controller: passCtrl);   // built-in show/hide
WBTextField.number(title: 'Quantity', controller: qtyCtrl);      // decimal keyboard
WBTextField.phone(title: 'Phone', initialCountryCode: '+20');    // country-code picker

Buttons #

WBButton(label: 'Save changes', onPressed: save);                    // primary
WBButton(label: 'Cancel', type: WBButtonType.secondary, onPressed: pop);
WBButton(label: 'Skip', type: WBButtonType.tertiary, onPressed: skip);

WBButton.icon(
  label: 'Continue',
  icon: Icons.arrow_forward,
  iconType: IconType.icon,
  isIconEnd: true,
  onPressed: next,
);

Colors follow Theme.primaryColor with a white foreground by default; pass backgroundColor/labelColor to override per-instance.

Images #

WBCachedImage(imageUrl: user.avatar, height: 120, fallback: const Icon(Icons.person));
WBUserImage(photo: user.avatar, displayName: user.name); // avatar, or initials fallback

WBCachedImage handles network / SVG / asset / file sources, fades in, and degrades to a fallback on error.

App infrastructure #

Debug environment switcher — repoint the API base URL at runtime without a rebuild. Inert in release builds, so a shipped app always boots into production.

// main.dart — before your DI/Dio is constructed
const production = WBAppEnvironment(name: 'prod', label: 'Production', baseUrl: prodUrl);

WBEnvironmentManager.init(
  WBEnvironmentConfig(
    environments: const [
      production,
      WBAppEnvironment(name: 'staging', label: 'Staging', baseUrl: stagingUrl),
    ],
    defaultEnvironment: production,
    persist: (env) => prefs.setString('env', env.name),
    read: () => prefs.getString('env'),
    onReinitialize: resetDependencies,
  ),
);
WBEnvironmentManager.loadPersisted();

runApp(const WBAppRestarter(child: MyApp())); // enables in-process restart
final baseUrl = WBEnvironmentManager.baseUrl; // always production in release builds
WBEnvironmentSwitcher.show(context);          // debug-only bottom sheet to pick an environment

Branding & version — drop-in footer widgets:

const WBPoweredBy();   // "Powered by …" mark
const WBAppVersion();  // app version + Shorebird patch number

Functions & extensions #

showToastSuccess(msg: 'Saved');
showToastError(msg: 'Something went wrong');

HexColor('#2563EB');                 // safe hex → Color (falls back to opaque white)

context.isArabic;  context.isDark;   // BuildContext helpers
context.bodySmall; context.titleLarge;

Migrating to the WB names #

The public widgets were rebranded with a consistent WB prefix. The previous names keep working through @Deprecated typedefs, so you can migrate incrementally:

Old name New name Old name New name
MainButton WBButton SmartScreen WBScreen
MainTextField WBTextField SmartEmptyWidget WBEmptyState
SmartLoadingWidget WBLoading SmartCachedImages WBCachedImage
SmartUserImage WBUserImage SmartTagWidget WBTag
StatusWidget WBStatus SmartStatusWidget WBPositionedStatus

Contributing #

Feel free to contribute. Found a bug or want a feature? Open an issue. Fixed something? Send a pull request.

Contributors

License #

Released under the MIT License.

3
likes
140
points
130
downloads
screenshot

Documentation

API reference

Publisher

verified publisherabdelrahman.ghanem.eg

Weekly Downloads

A Flutter package for efficient UI state management, handling loading, empty views, content display, caching, and pull-to-refresh with customizable widgets.

Homepage
Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

cached_network_image, country_code_picker, flutter, flutter_localizations, flutter_svg, intl, lottie, package_info_plus, phone_numbers_parser, shorebird_code_push, skeletonizer, smart_localize, url_launcher

More

Packages that depend on widgets_box