liquid_glass_ui_kit 0.1.2 copy "liquid_glass_ui_kit: ^0.1.2" to clipboard
liquid_glass_ui_kit: ^0.1.2 copied to clipboard

An accessible, customizable Liquid Glass design system for Flutter with translucent themes and ready-made widgets for mobile, web, and desktop.

Liquid Glass UI #

An iOS 26.4 "Liquid Glass" theme and component kit for Flutter. Drop in a frosted, translucent design system — colors, typography and ready-made widgets — and get the native-feeling glassmorphism look on any platform.

Everything is themeable through a single GlassTheme, and every component reads its blur, tint, rim-highlight and radii from that one place, so your whole app stays consistent.

Liquid Glass UI example showing cards, controls, overlays, and navigation

Live documentation · Source code · Report an issue

  • 🧊 Real BackdropFilter glass with a rim highlight and soft shadow
  • 🌗 Light & dark, monochrome by default (glass + white, no blue)
  • 🎞️ Smooth nav-bar animations (sliding bubble + springy pop), each toggleable
  • ⌨️ HIG-aligned text fields, settings toggles, and macOS autocomplete
  • ♿ Honors Reduce Transparency / Increase Contrast and Reduce Motion
  • 📦 Tiny, dependency-free (only the Flutter SDK)

Install #

dependencies:
  liquid_glass_ui_kit: ^0.1.2
import 'package:liquid_glass_ui_kit/liquid_glass_ui_kit.dart';

Quick start #

Wrap your app (or a subtree) in a GlassTheme, then use the components:

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

class HomePage extends StatefulWidget {
  const HomePage({super.key});
  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  int _tab = 0;

  @override
  Widget build(BuildContext context) {
    return GlassTheme(
      data: GlassThemeData.dark(),
      child: GlassScaffold(
        appBar: const GlassAppBar(title: Text('Home')),
        bottomNavigationBar: GlassBottomNavBar(
          currentIndex: _tab,
          onTap: (i) => setState(() => _tab = i),
          items: const [
            GlassNavItem(icon: Icons.home_rounded, label: 'Home'),
            GlassNavItem(icon: Icons.sports_esports_rounded, label: 'Arcade'),
            GlassNavItem(icon: Icons.group_rounded, label: 'Friends'),
            GlassNavItem(icon: Icons.inventory_2_rounded, label: 'Library'),
            GlassNavItem(icon: Icons.search_rounded, label: 'Search'),
          ],
        ),
        body: ListView(
          padding: const EdgeInsets.fromLTRB(16, 120, 16, 150),
          children: [
            GlassCard(child: Text('Frosted content')),
            const SizedBox(height: 16),
            GlassButton(
              label: 'Continue',
              variant: GlassButtonVariant.filled,
              expand: true,
              onPressed: () {},
            ),
          ],
        ),
      ),
    );
  }
}

Components at a glance #

Component What it is Key params
GlassSurface The core blurred/tinted/rim-lit panel everything is built on blurSigma, tint, highlight, borderRadius, shadow
GlassScaffold Page shell that floats bars over a scrollable body appBar, bottomNavigationBar, background, body
GlassAppBar Translucent top bar (PreferredSizeWidget) title, leading, actions, floating
GlassBottomNavBar Floating capsule tab bar with animated indicator items, currentIndex, onTap, animateIndicator, animateBounce, showLabels, borderRadius
GlassButton Capsule button — glass / filled / plain label, icon, variant, expand, onPressed
GlassCard Padded glass panel, optionally tappable child, padding, onTap
GlassPill Small tag / chip / filter label, icon, selected, onTap
GlassSwitch Native-behaving Apple switch for a binary setting value, onChanged, semanticLabel, activeTrackColor
GlassToggleRow HIG-recommended labeled list-row presentation for GlassSwitch label, description, value, onChanged
GlassTextField Apple-style short text entry with labels, Clear button, secure input, and validation label, placeholder, controller, keyboardType, validator
GlassComboBox<T> Editable macOS combo box with autocomplete and pull-down choices options, displayStringForOption, initialSelection, onChanged, onSelected
GlassSlider Slider with a translucent oversized glass thumb value, onChanged, min, max, divisions, activeColor
GlassSegmentedControl<T> Segmented tabs with a sliding, springy glass selection capsule children, selectedValue, onValueChanged, animateBounce
GlassSheet / showGlassBottomSheet Bottom sheet title, builder, heightFactor, showDragHandle
GlassDialog / showGlassDialog Alert popup title, message, actions
GlassActionMenu / showGlassActionMenu Anchored context menu items

Toggles and switches #

Apple's toggle guidance recommends using a switch for one pair of opposing states, clearly identifying what it affects, making its states visually distinct without relying only on color, and placing the switch in a list row on iOS and iPadOS.

Use GlassToggleRow for that standard presentation:

GlassToggleRow(
  label: 'Notifications',
  description: 'Allow alerts about new activity.',
  value: _notificationsEnabled,
  onChanged: (value) => setState(() => _notificationsEnabled = value),
),

Use the lower-level switch only when its parent already supplies the labeled row context:

GlassSwitch(
  value: _notificationsEnabled,
  semanticLabel: 'Notifications',
  onChanged: (value) => setState(() => _notificationsEnabled = value),
),

Both are controlled components. GlassSwitch uses native Cupertino mechanics, including tap and drag interaction, RTL direction, keyboard focus, platform haptics, VoiceOver state, and the system's On/Off Labels accessibility setting. For more than two choices, use a segmented control or another selection component instead.


The bottom nav bar & its animations #

GlassBottomNavBar is the signature piece. Two animations, each independently toggleable, and both auto-disabled under Reduce Motion:

Flag Default Effect
animateIndicator true The highlight slides ("bubbles") between items. Off → it just appears on the selected item.
animateBounce true The selected icon and pill pop with a spring. Off → no pop.
GlassBottomNavBar(
  currentIndex: _tab,
  onTap: (i) => setState(() => _tab = i),
  items: _items,

  // Animations — turn either off on its own:
  animateIndicator: true,   // sliding bubble
  animateBounce: true,      // springy pop (icon + pill)

  // Icons-only mode:
  showLabels: false,

  // Rounding — big values clamp to a full capsule:
  borderRadius: 40,             // the bar
  indicatorBorderRadius: 32,    // the pill (defaults to concentric with the bar)
)

You supply currentIndex and rebuild on onTap — it's a controlled widget, so the selection is your state.


Text fields #

GlassTextField follows Apple's text-field guidance: use it for small, specific values; keep a persistent label when the placeholder alone would be ambiguous; select the keyboard that matches the data; obscure sensitive input; and put useful validation feedback directly beside the field. A localized, Apple-style Clear button appears at the trailing edge when text is present.

import 'package:flutter/cupertino.dart' show CupertinoIcons;

GlassTextField(
  label: 'Email',
  placeholder: 'name@example.com',
  prefix: const Icon(CupertinoIcons.mail),
  keyboardType: TextInputType.emailAddress,
  textInputAction: TextInputAction.next,
  autofillHints: const [AutofillHints.email],
  validator: (value) => value != null && value.contains('@')
      ? null
      : 'Enter an email address, like name@example.com.',
),

GlassTextField(
  label: 'Password',
  placeholder: 'Required',
  obscureText: true,
  autocorrect: false,
  enableSuggestions: false,
  autofillHints: const [AutofillHints.password],
),

The field works with Flutter's Form, validator, onSaved, and AutovalidateMode APIs. Use inputFormatters for constrained values, and prefer a multiline text-view component when you need long-form input.

When you supply a controller or focusNode, you own and dispose it. Without them, GlassTextField manages its own instances. A custom trailing suffix replaces the Clear button, matching the underlying Cupertino behavior.


Autocomplete and dropdown combo boxes #

GlassComboBox<T> follows Apple's combo-box guidance: it combines an editable text field with a pull-down list, accepts custom input without adding it to the choices, supports a meaningful default, and keeps the choices panel exactly as wide as the field. Typing filters relevant choices; the trailing chevron opens the complete list.

GlassComboBox<String>(
  label: 'Favorite City:',
  placeholder: 'Enter a city',
  helperText: 'Choose a suggestion or type another city.',
  options: const ['Jakarta', 'London', 'San Francisco', 'Tokyo'],
  initialSelection: 'Jakarta',
  displayStringForOption: (city) => city,
  onChanged: (text) => setState(() => _city = text),
  onSelected: (city) => setState(() => _city = city),
),

Apple supports combo boxes on macOS, not iOS, iPadOS, tvOS, visionOS, or watchOS. On those platforms, prefer a platform-appropriate menu or selection flow. Keep the predefined choices relevant and short enough to read at the field's width.

Combo-box behavior #

Interaction Result
Type in the field Filters choices with a case-insensitive substring match; prefix matches appear first.
Press the chevron Opens every predefined choice.
Up / Down Moves the highlighted choice while the panel is open.
Enter Selects the highlighted or exact matching choice; otherwise submits custom text.
Escape or outside click Closes the choices panel.

Use optionFilter for domain-specific matching and optionBuilder for custom rows. onChanged receives typed and selected text, onSelected receives only a predefined T, and onSubmitted receives custom text. If you provide a controller or focusNode, their lifecycle remains yours.


Slider #

GlassSlider is a controlled range input. Rebuild it with the value received by onChanged; pass null to disable interaction. Use divisions when the value must snap to discrete steps, and always provide a meaningful semanticLabel.

GlassSlider(
  value: _volume,
  min: 0,
  max: 100,
  divisions: 20,
  activeColor: const Color(0xFF0A84FF),
  semanticLabel: 'Volume',
  onChanged: (value) => setState(() => _volume = value),
)

The white resting thumb expands to its full liquid-glass size while pressed or dragged. The control also supports arrow keys, Home/End, and screen-reader increment/decrement actions.


Tabs and segmented selection #

Use GlassSegmentedControl<T> for a small set of mutually exclusive views, filters, or modes inside the current screen. Use GlassBottomNavBar instead for top-level app destinations; its full API is documented in The bottom nav bar & its animations.

Like the slider, segmented tabs are controlled: update selectedValue from onValueChanged, or pass null to disable interaction.

GlassSegmentedControl<String>(
  children: const {
    'for-you': Text('For You'),
    'library': Text('Library'),
  },
  selectedValue: _section,
  onValueChanged: (value) => setState(() => _section = value),
  animateBounce: true,
)

Segmented tabs support taps, dragging across segments, RTL-aware Left/Right keys, and Home/End. The selection capsule and active label use the same springy bubble-pop motion as GlassBottomNavBar; set animateBounce: false to disable it independently. System Reduce Motion disables the animation automatically.


Overlays: sheet, dialog & menu #

All three need a Navigator / MaterialApp ancestor (as any modal route does).

// Bottom sheet
showGlassBottomSheet(
  context: context,
  title: 'Share',
  builder: (context) => Column(mainAxisSize: MainAxisSize.min, children: [...]),
);

// Popup dialog
showGlassDialog(
  context: context,
  title: 'Delete item?',
  message: 'This action cannot be undone.',
  actions: [
    GlassDialogAction(label: 'Cancel', isDefault: true, onPressed: () => Navigator.pop(context)),
    GlassDialogAction(label: 'Delete', isDestructive: true, onPressed: () => Navigator.pop(context)),
  ],
);

// Action menu — anchored to the widget owning `context`
showGlassActionMenu(
  context: context,
  items: [
    GlassMenuItem(label: 'Edit', icon: Icons.edit_outlined),
    GlassMenuItem(label: 'Delete', icon: Icons.delete_outline, isDestructive: true),
  ],
);

For the action menu, pass the trigger widget's own context (wrap it in a Builder) so the menu anchors to it and flips above when there's no room below.


Buttons #

GlassButton(label: 'Glass',  variant: GlassButtonVariant.glass,  onPressed: () {}),
GlassButton(label: 'Filled', variant: GlassButtonVariant.filled, onPressed: () {}),
GlassButton(label: 'Plain',  variant: GlassButtonVariant.plain,  onPressed: () {}),

// With an icon, full width, disabled:
GlassButton(
  label: 'Continue',
  icon: Icons.arrow_forward_rounded,
  variant: GlassButtonVariant.filled,
  expand: true,
  onPressed: null, // null disables it
);
  • glass — frosted capsule, accent-colored label
  • filled — solid accent capsule; label auto-picks black/white for contrast
  • plain — text-only, no fill

The building block: GlassSurface #

Compose your own frosted widgets with the same material:

GlassSurface(
  borderRadius: BorderRadius.circular(24),
  padding: const EdgeInsets.all(16),
  blurSigma: 30,           // override the theme blur
  tint: Colors.white24,    // override the tint
  child: const Text('Custom glass'),
)

Theming #

Grab the active theme anywhere with GlassTheme.of(context):

final theme = GlassTheme.of(context);
theme.colors.accent;      // monochrome accent
theme.colors.label;       // primary text/icon color
theme.typography.title1;  // type scale
theme.metrics.blurSigma;  // shared blur strength

Customize globally by passing your own GlassThemeData:

GlassTheme(
  data: GlassThemeData.light(
    metrics: const GlassMetrics(blurSigma: 32, largeRadius: 32),
  ).copyWith(
    // Opt into a color accent if you want one:
    colors: GlassColors.light.copyWith(accent: const Color(0xFFAF52DE)),
  ),
  child: ...,
)

Palettes #

The default accent is monochrome (graphite in light, near-white in dark), so out of the box it's pure glass + white with no color tint. GlassColors exposes: background, secondaryBackground, label, secondaryLabel, tertiaryLabel, accent, glassTint, glassHighlight, glassBorder, glassShadow, separator.

Follow the system light/dark mode #

GlassTheme(
  data: GlassThemeData(colors: GlassColors.of(context)),
  child: ...,
)

Metrics #

GlassMetrics centralizes blurSigma, borderWidth and the radii (smallRadius, mediumRadius, largeRadius, pillRadius) so you can dial the whole system up or down at once.

Fonts #

The package doesn't bundle SF Pro (Apple's license forbids redistribution). On Apple platforms Flutter renders with the system font automatically, so it looks native. To match it on Android/web, bundle your own font and apply it:

final typography = GlassTypography.forColors(GlassColors.dark)
    .apply(fontFamily: 'YourSFAlike');

GlassTheme(
  data: GlassThemeData(colors: GlassColors.dark, typography: typography),
  child: ...,
)

Accessibility #

Translucent UIs can fail WCAG contrast over busy backgrounds, so the kit honors the system settings automatically:

  • Reduce Transparency / Increase Contrast → glass surfaces drop the blur and render as opaque, clearly-bordered panels.
  • Reduce Motion → the press, toggle, nav, dialog and menu animations are disabled.

The default palette is monochrome and high-contrast (black/white text). Still, follow Apple's guidance: keep to roughly one glass layer per view, avoid stacking glass on glass, and verify text contrast over your real backgrounds.

The glass effect & performance #

GlassSurface uses a real BackdropFilter blur, so it needs content behind it to refract — float the bars over your body (as GlassScaffold does) rather than stacking them in a plain Column. Backdrop blurs are GPU work; a handful per screen is fine, but avoid dozens of overlapping ones in long lists.

Example #

The animation at the top of this page is captured from the full demo in example/. The current demo includes every component in light and dark mode, including the text field, labeled toggles, slider, segmented control, and autocomplete/dropdown combo box.

Run it locally:

cd example
flutter run

License #

MIT © 2026

1
likes
160
points
64
downloads
screenshot

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

An accessible, customizable Liquid Glass design system for Flutter with translucent themes and ready-made widgets for mobile, web, and desktop.

Repository (GitHub)
View/report issues

Topics

#ui #theme #glassmorphism #ios #cupertino

License

MIT (license)

Dependencies

flutter

More

Packages that depend on liquid_glass_ui_kit