WixzelUI

Wixzel UI for Flutter

wixzel_ui needs Flutter 3.41+ (Dart 3.11+). It brings the same tokens as the web packages, a ThemeData that stops stock Material from showing through (no ripples, no elevation, no M3 tints), and Wx* widgets with the Wixzel details: squircle corners, press-to-shrink, blur-in entrances, the ring spinner.

Install

flutter pub add wixzel_ui

If the package isn't on pub.dev yet in the user's environment, depend on Git:

dependencies:
  wixzel_ui:
    git:
      url: https://github.com/wixzel/wixzel-ui.git
      path: packages/flutter

It brings google_fonts (Manrope) and phosphor_flutter (icons) with it.

Foundation

import 'package:flutter/material.dart';
import 'package:wixzel_ui/wixzel_ui.dart';

// The project's brand colour. One seed derives the whole palette, both themes.
final brand = wxDeriveProduct(const Color(0xFFE4572E));

class App extends StatelessWidget {
  const App({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: WixzelTheme.custom(tokens: brand).toThemeData(),
      darkTheme: WixzelTheme.custom(tokens: brand, brightness: Brightness.dark).toThemeData(),
      themeMode: ThemeMode.system,
      builder: (context, child) => WxSystemBars(child: child!),
      home: const HomeScreen(),
    );
  }
}

wxDeriveProduct(seed, {tint = 0.45, hue, radius = 1, fontFamily}) is the same derivation as the web's deriveProduct, so a seed gives identical colours on both. fontFamily must be a Google Fonts family name.

Replace any existing ThemeData(colorScheme: ColorScheme.fromSeed(...)), FlexColorScheme, or hand-built theme with this. Delete per-widget style: ElevatedButton.styleFrom(...) overrides as each screen moves over.

Reading tokens in your own widgets

final c = context.wx;        // WxColors: bg, bgSubtle, card, bgMuted, fg, fgMuted, accent, accentInk, accentEdge, dangerInk …
final t = context.wxType;    // headingLg, headingMd, bodyMd, bodySm, caption, overline, mono …
final s = context.wxShape;   // squircle borders: xs, sm, md (controls), lg (panels), xl (dialogs)
final sh = context.wxShadows;

DecoratedBox(decoration: ShapeDecoration(color: c.card, shape: s.lg), child: …);
Text('Calls today', style: t.headingMd);

Spacing and sizes: WxControl.md (38), WxRadius, WxSquircle, durations in WxDurations (instant 70ms, fast 110ms, move 150ms, enter 270ms) and curves in WxEase.

Icons

const PhosphorIcon(PhosphorIconsDuotone.gear)

Swap Icons.* (Material) and Cupertino icons for the Phosphor duotone equivalent by meaning: Icons.settings → PhosphorIconsDuotone.gear, Icons.search → magnifyingGlass, Icons.delete → trash, Icons.add → PhosphorIconsBold.plus inside buttons.

Widgets

NeedWixzelReplaces
ButtonWxButton(label:, onPressed:, variant:, size:, loading:, iconStart:, iconEnd:, block:) — variants primary secondary ghost danger linkElevatedButton, FilledButton, OutlinedButton, TextButton, CupertinoButton
Icon buttonWxIconButton(icon:, onPressed:, tooltip:)IconButton
Text fieldWxInput(controller:, label:, placeholder:, hint:, error:, leading:, trailing:)TextField, TextFormField
Label + hint + error around any controlWxField(label:, hint:, error:, child:)InputDecorator
SelectWxSelect(options: [WxSelectOption(v, 'Label')], value:, onChanged:); free-form showWxPickerDropdownButton, DropdownMenu
Checkbox, radio, switchWxCheckbox, WxRadio, WxSwitchCheckbox, Radio, Switch
Settings rowsWxListRow, WxSwitchRow, WxCheckboxRow, WxRadioRowListTile, SwitchListTile, CheckboxListTile, RadioListTile
Option cardsWxRadioCard(selected:, onTap:, title:, description:)custom selectable cards
Filter chipsWxChips(children: [WxChip(label:, selected:, onTap:, count:)])FilterChip, ChoiceChip
CardWxCard(child:, onTap:, selected:)Card (drop elevation)
Settings groupWxSection(title:, description:, icon:, children:, tone:)Card of ListTiles
App barWxAppBar(title:, actions:, bottom:)AppBar, SliverAppBar
Bottom navigationWxBottomNav(items: [WxBottomNavItem(icon:, label:)], currentIndex:, onTap:)BottomNavigationBar, NavigationBar
TabsWxTabs(controller:, tabs:, variant: WxTabsVariant.line | segment)TabBar, CupertinoSegmentedControl
DialogshowWxDialog(context: , builder: (_) => WxDialog(title:, description:, actions:))showDialog + AlertDialog
Bottom sheetshowWxSheet(context:, builder:)showModalBottomSheet
ToastshowWxToast(context, 'Saved', tone: WxToastTone.success)ScaffoldMessenger.showSnackBar
AlertWxAlert(tone: WxTone.warning, title:, body:, action:)MaterialBanner
BadgeWxBadge (tones neutral accent success warning danger info)Badge, Chip used as status
AvatarWxAvatar(name:, size:, status:)CircleAvatar
LoadingWxSpinner, WxSkeleton, WxRefreshCircularProgressIndicator, RefreshIndicator
Empty listWxEmptyState(icon:, title:, description:, actions:)ad-hoc centred columns
MetricWxStatCard(label:, value:, icon:, footer:)
Icon on a tileWxIconTile(icon:, tone:)CircleAvatar holding an icon
Secret, API keyWxCopyField(value:, secret: true)
Chat bubbleWxMessage(from: WxMessageFrom.agent | person, child:, streaming:)
DividerWxSeparatorDivider

Your own interactive widgets

Wrap them in WxPressable(builder: (context, state) => …, onTap:): it shrinks to 96% on press, eases back, and gives state.hovered / state.focused for the one-shade-darker fill. Bring new content in with WxBlurIn. Clip panels with context.wxShape.lg, never BorderRadius.circular on a Container with a BoxShadow.