Liquid Glass Widgets

A comprehensive Flutter package implementing Apple's Liquid Glass design system with 32 beautiful, composable glass-morphic widgets.

pub package License: MIT

https://github.com/user-attachments/assets/2fe28f46-96ad-459d-b816-e6d6001d90de

Features

  • 32 Widgets organized into six categories
  • Two Quality Modes for performance optimization
  • Flexible Layer System for efficient rendering
  • Highly Customizable appearance with extensive glass settings
  • Apple Design Guidelines faithful implementation
  • Fully Tested with widget tests and golden visual regression tests

Widget Categories

Containers

Foundation primitives for content layout:

  • GlassContainer - Base primitive with configurable dimensions and shape
  • GlassCard - Elevated card with shadow for content grouping
  • GlassPanel - Larger surface for major UI sections

Interactive

User interaction components:

  • GlassButton - Primary action button
  • GlassIconButton - Icon-based button
  • GlassChip - Tag/category indicator
  • GlassSwitch - Toggle control
  • GlassSlider - Range selection
  • GlassSegmentedControl - Multi-option selector
  • GlassPullDownButton - Menu trigger button with dropdown
  • GlassButtonGroup - Container for grouping related buttons
  • GlassBadge - Notification count and status dot indicators

Input

Text input components:

  • GlassTextField - Text input field
  • GlassTextArea - Multi-line text input area
  • GlassPasswordField - Secure text input with visibility toggle
  • GlassSearchBar - Search-specific input
  • GlassPicker - Scrollable item selector
  • GlassFormField - Form field wrapper for validation

Feedback

Status and loading indicators:

  • GlassProgressIndicator - Circular and linear progress indicators
  • GlassToast / GlassSnackBar - Toast notifications with auto-dismiss and actions

Overlays

Modal and floating UI:

  • GlassDialog - Modal dialog
  • GlassSheet - Bottom sheet / modal sheet
  • GlassActionSheet - iOS-style bottom action picker
  • GlassMenu - iOS 26 morphing context menu
  • GlassMenuItem - Individual menu action item

Surfaces

Navigation and app structure:

  • GlassAppBar - Top app bar
  • GlassBottomBar - Bottom navigation bar
  • GlassTabBar - Tab navigation bar
  • GlassSideBar - Vertical navigation sidebar
  • GlassToolbar - Action toolbar for tools and controls
showcase

Installation

Add to your pubspec.yaml:

dependencies:
  liquid_glass_widgets: ^0.4.0-dev.4

Then run:

flutter pub get

Quick Start

Preventing White Flash (Important!)

To eliminate the brief white flash when glass widgets first appear, precache the lightweight shader at app startup:

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

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await LiquidGlassWidgets.initialize();

  runApp(const MyApp());
}

Basic Usage

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: GlassContainer(
            width: 200,
            height: 100,
            child: Text('Hello, Glass!'),
          ),
        ),
      ),
    );
  }
}

When you have multiple glass widgets, wrap them in an AdaptiveLiquidGlassLayer for better performance:

AdaptiveLiquidGlassLayer(
  settings: LiquidGlassSettings(
    thickness: 0.8,
    blur: 12.0,
    glassColor: Colors.white.withOpacity(0.1),
  ),
  child: Column(
    children: [
      GlassContainer(
        child: Text('First glass widget'),
      ),
      GlassButton(
        onPressed: () {},
        child: Text('Click me'),
      ),
      GlassCard(
        child: Text('Another glass widget'),
      ),
    ],
  ),
)

Standalone Widget (For Single Glass Elements)

For a single glass widget or when you need different settings per widget:

GlassContainer(
  useOwnLayer: true,
  settings: LiquidGlassSettings(
    thickness: 1.0,
    blur: 15.0,
  ),
  child: Text('Standalone glass widget'),
)

Platform Support

This package works seamlessly across all Flutter platforms with optimized rendering:

  • iOS (Native Impeller & Skia)
  • Android (Native Impeller & Skia)
  • macOS (Native Impeller & Skia)
  • Web (CanvasKit with per-widget shader instances)
  • Windows (Skia)
  • Linux (Skia)

Adaptive Rendering:

  • Impeller (iOS/Android): Full shader pipeline with texture capture and chromatic aberration
  • Skia & Web: High-performance lightweight fragment shader
  • Platform detection is automatic—no configuration needed

Glass Quality Modes

The package provides two quality modes optimized for different use cases:

GlassContainer(
  quality: GlassQuality.standard,
  child: Text('Great for scrollable content'),
)
  • Uses lightweight fragment shader for iOS 26 accurate glass effects
  • Works universally across all platforms (native, Skia, web)
  • Use for: Lists, forms, scrollable content, interactive widgets
  • Recommended default for 95% of use cases

Premium Quality (Static Layouts Only)

GlassAppBar(
  quality: GlassQuality.premium,
  title: Text('Static header with premium quality'),
)
  • Impeller (iOS/macOS native): Full shader pipeline with texture capture and chromatic aberration
  • Skia/Web: Automatically falls back to lightweight shader (same as standard quality)
  • Higher visual quality on capable platforms
  • Use only for: Static, non-scrollable layouts (app bars, bottom bars, hero sections)
  • Warning: May not render correctly in scrollable contexts on Impeller

Theming

All widgets support automatic theming with light/dark mode switching via GlassTheme:

GlassTheme(
  data: GlassThemeData(
    light: GlassThemeVariant(
      settings: LiquidGlassSettings(
        thickness: 30,
        blur: 12,
        lightIntensity: 2.0,
      ),
      quality: GlassQuality.standard,
      glowColors: GlassGlowColors(
        primary: Colors.blue.withOpacity(0.3),
        secondary: Colors.purple.withOpacity(0.3),
        success: Colors.green.withOpacity(0.3),
        warning: Colors.orange.withOpacity(0.3),
        danger: Colors.red.withOpacity(0.3),
      ),
    ),
    dark: GlassThemeVariant(
      settings: LiquidGlassSettings(
        thickness: 50,
        blur: 18,
        lightIntensity: 3.0,
      ),
      quality: GlassQuality.premium,
      glowColors: GlassGlowColors(
        primary: Colors.cyan.withOpacity(0.4),
        secondary: Colors.purple.withOpacity(0.4),
        success: Colors.teal.withOpacity(0.4),
        warning: Colors.amber.withOpacity(0.4),
        danger: Colors.deepOrange.withOpacity(0.4),
      ),
    ),
  ),
  child: MaterialApp(
    home: MyHomePage(),
  ),
)

Widgets automatically inherit theme settings:

// Uses theme settings and glow colors automatically
GlassButton(
  onPressed: () {},
  child: Text('Themed Button'),
)

// Override theme for specific widget
GlassButton(
  onPressed: () {},
  glowColor: Colors.pink,  // Explicit override
  child: Text('Custom Glow'),
)

Access theme programmatically:

final themeData = GlassThemeData.of(context);
final variant = themeData.variantFor(context);  // Gets light/dark based on MediaQuery

Progress Indicators

GlassProgressIndicator provides iOS 26-compliant loading and progress feedback with Liquid Glass effects. Available in both circular and linear variants, with indeterminate (loading) and determinate (progress tracking) modes.

Circular Progress Indicators

Indeterminate Spinner (Loading):

// Default medium size (20pt)
GlassProgressIndicator.circular()

// Different sizes
GlassProgressIndicator.circular(
  size: 14.0,       // Small
  strokeWidth: 2.0,
)

GlassProgressIndicator.circular(
  size: 28.0,       // Large
  strokeWidth: 3.0,
)

Determinate Ring (Progress 0-100%):

double progress = 0.7; // 70% complete

GlassProgressIndicator.circular(
  value: progress,
  color: Colors.green,
)

Linear Progress Indicators

Indeterminate Bar (Loading):

GlassProgressIndicator.linear()

// Custom height
GlassProgressIndicator.linear(
  height: 6.0,
  color: Colors.blue,
)

Determinate Bar (Progress 0-100%):

double uploadProgress = 0.5; // 50% complete

GlassProgressIndicator.linear(
  value: uploadProgress,
  color: uploadProgress == 1.0 ? Colors.green : Colors.blue,
)

Real-World Example: File Upload

class UploadDemo extends StatefulWidget {
  @override
  State<UploadDemo> createState() => _UploadDemoState();
}

class _UploadDemoState extends State<UploadDemo> {
  double _uploadProgress = 0.0;
  bool _isUploading = false;

  void _startUpload() {
    setState(() => _isUploading = true);

    // Simulate upload with timer
    Timer.periodic(Duration(milliseconds: 50), (timer) {
      setState(() {
        _uploadProgress += 0.01;
        if (_uploadProgress >= 1.0) {
          _uploadProgress = 1.0;
          _isUploading = false;
          timer.cancel();
        }
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        GlassProgressIndicator.linear(
          value: _uploadProgress,
          color: _uploadProgress == 1.0 ? Colors.green : Colors.blue,
        ),
        SizedBox(height: 16),
        GlassButton(
          onPressed: _isUploading ? null : _startUpload,
          child: Text(_isUploading ? 'Uploading...' : 'Start Upload'),
        ),
      ],
    );
  }
}

iOS 26 Specifications

GlassProgressIndicator implements exact iOS 26 Liquid Glass specifications:

  • Circular: 20pt diameter (default), 2.5pt stroke width, 1.0s rotation
  • Linear: Full width, 4pt height (default)
  • Glass Effects: Translucent background (15% white), color glow with 4pt blur
  • Theme Integration: Automatically uses theme's primary glow color
  • Sizes: Small (14pt), Medium (20pt/default), Large (28pt)

Customization

All glass widgets accept a settings parameter (in standalone mode) or inherit from parent LiquidGlassLayer:

LiquidGlassSettings(
  thickness: 0.8,              // Material thickness (0.0-1.0)
  blur: 12.0,                  // Blur radius
  refractiveIndex: 1.5,        // Light refraction (1.0-2.0)
  glassColor: Colors.white.withOpacity(0.1), // Tint color
  lightAngle: 45.0,            // Directional lighting angle
  lightIntensity: 0.8,         // Lighting strength
  ambientStrength: 0.3,        // Ambient light contribution
  saturation: 1.2,             // Color saturation multiplier
  chromaticAberration: 0.002,  // Color separation effect
)

Widget Examples

Button with Action

GlassButton(
  onPressed: () {
    print('Button pressed!');
  },
  padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12),
  child: Text('Click Me'),
)

Text Input Field

GlassTextField(
  hintText: 'Enter your name',
  onChanged: (value) {
    print('Text changed: $value');
  },
)
showDialog(
  context: context,
  builder: (context) => GlassDialog(
    title: Text('Confirm'),
    content: Text('Are you sure?'),
    actions: [
      GlassButton(
        onPressed: () => Navigator.pop(context),
        child: Text('Cancel'),
      ),
      GlassButton(
        onPressed: () {
          // Handle confirm
          Navigator.pop(context);
        },
        child: Text('OK'),
      ),
    ],
  ),
);

Bottom Sheet

showModalBottomSheet(
  context: context,
  backgroundColor: Colors.transparent,
  builder: (context) => GlassSheet(
    child: Column(
      children: [
        ListTile(title: Text('Option 1')),
        ListTile(title: Text('Option 2')),
        ListTile(title: Text('Option 3')),
      ],
    ),
  ),
);

Segmented Control

GlassSegmentedControl(
  segments: ['Day', 'Week', 'Month'],
  selectedIndex: 0,
  onChanged: (index) {
    print('Selected segment: $index');
  },
)

Complete Example

See the example directory for a full showcase app demonstrating all widgets. Run it with:

cd example
flutter run

Architecture

Layer System

All widgets support two rendering modes:

  • Grouped Mode (useOwnLayer: false, default): Multiple widgets share the same rendering context via parent AdaptiveLiquidGlassLayer. More performant for many glass elements.

  • Standalone Mode (useOwnLayer: true): Each widget creates its own independent rendering context. Use for single widgets or different settings per widget.

Shape System

Widgets use LiquidShape for customizable shapes, with LiquidRoundedSuperellipse (16px radius) as the default for a smooth, modern appearance.

Performance Tips

  1. Precache the shader at app startup with await LiquidGlassWidgets.initialize(); to eliminate loading flash
  2. Use Grouped Mode when you have multiple glass widgets - wrap them in AdaptiveLiquidGlassLayer
  3. Use Standard Quality for scrollable content and interactive widgets (it's already very high quality!)
  4. Reserve Premium Quality for static elements like app bars where you want Impeller's advanced features
  5. Limit glass widget depth - avoid deeply nesting glass effects

Custom Refraction for Interactive Indicators

Interactive widgets like GlassSegmentedControl can have true liquid glass refraction (background visible through the indicator with edge distortion) on all platforms including Web and Skia.

Use the LiquidGlassScope.stack convenience constructor to eliminate boilerplate:

LiquidGlassScope.stack(
  background: Image.asset('assets/wallpaper.jpg', fit: BoxFit.cover),
  content: Scaffold(
    body: Center(
      child: GlassSegmentedControl(
        segments: ['Option A', 'Option B', 'Option C'],
        selectedIndex: 0,
        onSegmentSelected: (index) => print('Selected: $index'),
        quality: GlassQuality.standard,  // Uses custom shader
      ),
    ),
  ),
)

Manual Setup (More Control)

For custom layouts, use the manual pattern:

LiquidGlassScope(
  child: Stack(
    children: [
      // 1. Mark the background for capture
      Positioned.fill(
        child: LiquidGlassBackground(
          child: Image.asset('assets/wallpaper.jpg', fit: BoxFit.cover),
        ),
      ),
      
      // 2. Glass widgets will refract through the background
      Center(
        child: GlassSegmentedControl(
          segments: ['Option A', 'Option B', 'Option C'],
          selectedIndex: 0,
          onSegmentSelected: (index) => print('Selected: $index'),
          quality: GlassQuality.standard,  // Uses custom shader
        ),
      ),
    ],
  ),
)

Key Points

  • LiquidGlassScope.stack - Convenience constructor that eliminates boilerplate (recommended)
  • LiquidGlassScope - Creates the infrastructure for background capture
  • LiquidGlassBackground - Marks which content should be visible through the glass
  • Nested Scopes - Inner scopes override outer scopes (useful for isolated demos)
  • Automatic on Impeller - On iOS/macOS with Impeller, GlassQuality.premium uses native scene graph instead
  • One Background Per Scope - Each LiquidGlassScope should contain only one LiquidGlassBackground

When to Use

Scenario Recommendation
Web / Skia platforms ✅ Use LiquidGlassScope.stack for refraction
iOS / macOS with Impeller ⚡ Use GlassQuality.premium for native scene graph
Multiple isolated demo sections 🔄 Use separate scopes for each
App-wide fallback 🏠 Wrap root with LiquidGlassScope.stack

💡 Tip: Run the example app on an Impeller device (iOS/macOS) to see a side-by-side comparison of Impeller vs Custom Shader rendering in the "Shader Comparison" section of the Interactive page for GlassSegmentedControl.

Dependencies

This package builds on the excellent work of:

liquid_glass_renderer

Powers the Impeller integration for native scene graph rendering on iOS/Android/macOS with GlassQuality.premium. This sophisticated renderer provides texture capture and advanced chromatic aberration effects through Impeller's native pipeline.

For Skia and Web platforms, this package uses custom fragment shaders (lightweight_glass.frag, interactive_indicator.frag) to deliver iOS 26-accurate glass effects universally.

A huge thank you to the whynotmake-it team for creating the Impeller integration that makes premium-quality glass rendering possible on native platforms.

Other Dependencies

  • motor - Animation utilities

Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

Testing

# Run all tests
flutter test

# Run excluding golden tests
flutter test --exclude-tags golden

# Run golden tests only (macOS)
flutter test --tags golden

License

This project is licensed under the MIT License - see the LICENSE file for details.

Credits

This package implements Apple's Liquid Glass design guidelines as a high-level widget library.

Special Thanks:

  • The whynotmake-it team for creating the liquid_glass_renderer package, which provides the sophisticated shader-based rendering engine that powers all the glass effects in this library. Their work on custom shaders, texture capture, and advanced glass rendering techniques made this widget library possible.

Libraries

constants/glass_defaults
Common constants used throughout the liquid_glass_widgets package.
liquid_glass_setup
liquid_glass_widgets
Liquid Glass Implementation according to Apple's Guidelines
theme/glass_theme
theme/glass_theme_data
theme/glass_theme_helpers
types/glass_button_style
types/glass_quality
utils/draggable_indicator_physics
widgets/containers/glass_card
widgets/containers/glass_container
widgets/containers/glass_panel
widgets/feedback/glass_progress_indicator
widgets/input/glass_form_field
widgets/input/glass_password_field
widgets/input/glass_picker
widgets/input/glass_text_area
widgets/input/glass_text_field
widgets/interactive/glass_badge
widgets/interactive/glass_button
widgets/interactive/glass_button_group
widgets/interactive/glass_chip
widgets/interactive/glass_icon_button
widgets/interactive/glass_pull_down_button
widgets/interactive/glass_segmented_control
widgets/interactive/glass_slider
widgets/interactive/glass_switch
widgets/interactive/liquid_glass_scope
widgets/overlays/glass_action_sheet
widgets/overlays/glass_dialog
widgets/overlays/glass_menu
widgets/overlays/glass_menu_item
widgets/overlays/glass_sheet
widgets/overlays/glass_toast
widgets/shared/adaptive_glass
widgets/shared/adaptive_liquid_glass_layer
widgets/shared/animated_glass_indicator
widgets/shared/glass_effect
widgets/shared/inherited_liquid_glass
widgets/shared/lightweight_liquid_glass
widgets/surfaces/glass_app_bar
widgets/surfaces/glass_bottom_bar
widgets/surfaces/glass_side_bar
widgets/surfaces/glass_tab_bar
widgets/surfaces/glass_toolbar