liqkit_ui
Containers

Sheets

LiqSheet is the iOS 26 modal sheet container. It renders the grabber, controls row, and body for the chosen LiqSheetVariant. The host is responsible for animating presentation and dimming the parent scrim.

Full Screen

// ignore_for_file: file_namesimport 'package:docs_snippets/src/snippet_frame.dart';import 'package:flutter/widgets.dart';import 'package:liqkit_ui/examples.dart';Widget sheetFullScreenBuilder(BuildContext context) {  return const SnippetFrame(child: SheetFullScreenExample());}

Stacked

import 'package:docs_snippets/src/snippet_frame.dart';import 'package:flutter/widgets.dart';import 'package:liqkit_ui/liqkit_ui.dart';/// Snippet builder consumed by `apps/docs_snippets/lib/src/routes.g.dart`.Widget sheetStackedBuilder(BuildContext context) {  return const _SheetStackedDemo();}class _SheetStackedDemo extends StatefulWidget {  const _SheetStackedDemo();  @override  State<_SheetStackedDemo> createState() => _SheetStackedDemoState();}class _SheetStackedDemoState extends State<_SheetStackedDemo> {  bool _presented = true;  @override  Widget build(BuildContext context) {    return SnippetFrame(      maxWidth: 430,      height: 500,      padding: const EdgeInsets.symmetric(horizontal: 12),      surface: SnippetFrameSurface.liquidThemed,      surfacePadding: EdgeInsets.zero,      surfaceScrimOpacity: 0.18,      child: Stack(        alignment: Alignment.bottomCenter,        children: <Widget>[          _StackedBackdrop(onPressed: () => setState(() => _presented = true)),          AnimatedSlide(            offset: _presented ? Offset.zero : const Offset(0, 1.1),            duration: LiqMotion.normal,            curve: LiqMotion.snappy,            child: AnimatedOpacity(              opacity: _presented ? 1 : 0,              duration: LiqMotion.fast,              child:              LiqSheet(                title: 'Payment',                variant: LiqSheetVariant.stacked,                height: 430,                leading: LiqSheetTopButton(                  semanticsLabel: 'Close',                  onPressed: () => setState(() => _presented = false),                  child: const Text('x'),                ),                trailing: LiqSheetTopButton(                  style: LiqSheetTopButtonStyle.primary,                  semanticsLabel: 'Confirm',                  onPressed: () => setState(() => _presented = false),                  child: const Text('OK'),                ),                child: const _PaymentSheetBody(),              ),            ),          ),        ],      ),    );  }}class _StackedBackdrop extends StatelessWidget {  const _StackedBackdrop({required this.onPressed});  final VoidCallback onPressed;  @override  Widget build(BuildContext context) {    return Padding(      padding: const EdgeInsets.all(18),      child: Column(        crossAxisAlignment: CrossAxisAlignment.stretch,        children: <Widget>[          const SnippetLabel(            'Checkout',            fontSize: 28,            fontWeight: FontWeight.w700,          ),          const SizedBox(height: 12),          const _InvoiceCard(),          const Spacer(),          LiqButton(label: 'Show stacked sheet', onPressed: onPressed),        ],      ),    );  }}class _InvoiceCard extends StatelessWidget {  const _InvoiceCard();  @override  Widget build(BuildContext context) {    final isDark = LiqTheme.maybeOf(context)?.brightness == Brightness.dark;    return Container(      padding: const EdgeInsets.all(16),      decoration: BoxDecoration(        color: isDark ? const Color(0xFF2C2C2E) : const Color(0xFFF2F2F7),        borderRadius: const BorderRadius.all(Radius.circular(18)),      ),      child: const Column(        crossAxisAlignment: CrossAxisAlignment.stretch,        children: <Widget>[          _LineItem(label: 'Liqkit Pro', value: r'$24'),          _LineItem(label: 'Tax', value: r'$2'),          _LineItem(label: 'Total', value: r'$26', strong: true),        ],      ),    );  }}class _PaymentSheetBody extends StatelessWidget {  const _PaymentSheetBody();  @override  Widget build(BuildContext context) {    final isDark = LiqTheme.maybeOf(context)?.brightness == Brightness.dark;    return Padding(      padding: const EdgeInsets.fromLTRB(22, 8, 22, 22),      child: Column(        crossAxisAlignment: CrossAxisAlignment.stretch,        children: <Widget>[          const _LineItem(label: 'Card', value: 'Apple Pay', strong: true),          const _LineItem(label: 'Billing cycle', value: 'Monthly'),          const _LineItem(label: 'Due today', value: r'$26', strong: true),          const SizedBox(height: 18),          Text(            'Stacked sheets show the previous modal page tucked underneath, '            'making layered presentation obvious.',            textDirection: TextDirection.ltr,            style: TextStyle(              color: isDark ? const Color(0xFFA1A1AA) : const Color(0xFF6E6E73),              fontSize: 15,              height: 1.35,            ),          ),        ],      ),    );  }}class _LineItem extends StatelessWidget {  const _LineItem({    required this.label,    required this.value,    this.strong = false,  });  final String label;  final String value;  final bool strong;  @override  Widget build(BuildContext context) {    final isDark = LiqTheme.maybeOf(context)?.brightness == Brightness.dark;    return Padding(      padding: const EdgeInsets.symmetric(vertical: 10),      child: Row(        children: <Widget>[          Expanded(            child: Text(              label,              textDirection: TextDirection.ltr,              style: TextStyle(                fontSize: 15,                color:                    isDark ? const Color(0xFFA1A1AA) : const Color(0xFF6E6E73),              ),            ),          ),          Text(            value,            textDirection: TextDirection.ltr,            style: TextStyle(              color: isDark ? const Color(0xFFF5F5F7) : const Color(0xFF1A1A1A),              fontSize: 15,              fontWeight: strong ? FontWeight.w700 : FontWeight.w500,            ),          ),        ],      ),    );  }}

Inspector

import 'package:docs_snippets/src/snippet_frame.dart';import 'package:flutter/widgets.dart';import 'package:liqkit_ui/liqkit_ui.dart';/// Snippet builder consumed by `apps/docs_snippets/lib/src/routes.g.dart`.Widget sheetInspectorBuilder(BuildContext context) {  return const _SheetInspectorDemo();}class _SheetInspectorDemo extends StatefulWidget {  const _SheetInspectorDemo();  @override  State<_SheetInspectorDemo> createState() => _SheetInspectorDemoState();}class _SheetInspectorDemoState extends State<_SheetInspectorDemo> {  bool _presented = true;  @override  Widget build(BuildContext context) {    return SnippetFrame(      maxWidth: 430,      height: 540,      padding: const EdgeInsets.symmetric(horizontal: 12),      surface: SnippetFrameSurface.liquidThemed,      surfacePadding: EdgeInsets.zero,      surfaceScrimOpacity: 0.12,      child: Stack(        alignment: Alignment.bottomCenter,        children: <Widget>[          _InspectorCanvas(onPressed: () => setState(() => _presented = true)),          AnimatedSlide(            offset: _presented ? Offset.zero : const Offset(0, 1.1),            duration: LiqMotion.normal,            curve: LiqMotion.snappy,            child: AnimatedOpacity(              opacity: _presented ? 1 : 0,              duration: LiqMotion.fast,              child:              LiqSheet(                title: 'Inspector',                variant: LiqSheetVariant.inspector,                leading: LiqSheetTopButton(                  semanticsLabel: 'Close',                  onPressed: () => setState(() => _presented = false),                  child: const Text('x'),                ),                trailing: LiqSheetTopButton(                  style: LiqSheetTopButtonStyle.primary,                  semanticsLabel: 'Apply',                  onPressed: () => setState(() => _presented = false),                  child: const Text('OK'),                ),                child: const _InspectorSheetBody(),              ),            ),          ),        ],      ),    );  }}class _InspectorCanvas extends StatelessWidget {  const _InspectorCanvas({required this.onPressed});  final VoidCallback onPressed;  @override  Widget build(BuildContext context) {    return Padding(      padding: const EdgeInsets.all(18),      child: Column(        crossAxisAlignment: CrossAxisAlignment.stretch,        children: <Widget>[          const SnippetLabel(            'Photo',            fontSize: 28,            fontWeight: FontWeight.w700,          ),          const SizedBox(height: 14),          const Expanded(            child: DecoratedBox(              decoration: BoxDecoration(                borderRadius: BorderRadius.all(Radius.circular(22)),                gradient: LinearGradient(                  begin: Alignment.topLeft,                  end: Alignment.bottomRight,                  colors: <Color>[                    Color(0xFFFF6B8A),                    Color(0xFF2F8DFF),                    Color(0xFF58D68D),                  ],                ),                boxShadow: <BoxShadow>[                  BoxShadow(color: Color(0x22000000), blurRadius: 20),                ],              ),            ),          ),          const SizedBox(height: 14),          LiqButton(label: 'Show inspector', onPressed: onPressed),        ],      ),    );  }}class _InspectorSheetBody extends StatelessWidget {  const _InspectorSheetBody();  @override  Widget build(BuildContext context) {    final isDark = LiqTheme.maybeOf(context)?.brightness == Brightness.dark;    return Padding(      padding: const EdgeInsets.fromLTRB(22, 4, 22, 20),      child: Column(        crossAxisAlignment: CrossAxisAlignment.stretch,        children: <Widget>[          const _InspectorControl(label: 'Exposure', value: '+0.4'),          const _InspectorControl(label: 'Contrast', value: '18%'),          const _InspectorControl(label: 'Warmth', value: 'Neutral'),          const SizedBox(height: 12),          Text(            'Inspector sheets float over the content they adjust, using a '            'glass surface so the edited object remains visible.',            textDirection: TextDirection.ltr,            style: TextStyle(              color: isDark ? const Color(0xFFA1A1AA) : const Color(0xFF6E6E73),              fontSize: 15,              height: 1.35,            ),          ),        ],      ),    );  }}class _InspectorControl extends StatelessWidget {  const _InspectorControl({required this.label, required this.value});  final String label;  final String value;  @override  Widget build(BuildContext context) {    final isDark = LiqTheme.maybeOf(context)?.brightness == Brightness.dark;    return Container(      margin: const EdgeInsets.only(bottom: 8),      padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12),      decoration: BoxDecoration(        color: isDark ? const Color(0x3DFFFFFF) : const Color(0x4DFFFFFF),        borderRadius: const BorderRadius.all(Radius.circular(12)),      ),      child: Row(        children: <Widget>[          Expanded(            child: Text(              label,              textDirection: TextDirection.ltr,              style: TextStyle(                color:                    isDark ? const Color(0xFFF5F5F7) : const Color(0xFF1A1A1A),                fontSize: 15,              ),            ),          ),          Text(            value,            textDirection: TextDirection.ltr,            style: TextStyle(              color: isDark ? const Color(0xFFF5F5F7) : const Color(0xFF1A1A1A),              fontSize: 15,              fontWeight: FontWeight.w600,            ),          ),        ],      ),    );  }}

Bottom

// ignore_for_file: file_namesimport 'package:docs_snippets/src/snippet_frame.dart';import 'package:flutter/widgets.dart';import 'package:liqkit_ui/examples.dart';Widget sheetBottomBuilder(BuildContext context) {  return const SnippetFrame(child: SheetBottomExample());}

Action

// ignore_for_file: file_namesimport 'package:docs_snippets/src/snippet_frame.dart';import 'package:flutter/widgets.dart';import 'package:liqkit_ui/examples.dart';Widget sheetActionBuilder(BuildContext context) {  return const SnippetFrame(child: SheetActionExample());}

Compact Action

// ignore_for_file: file_namesimport 'package:docs_snippets/src/snippet_frame.dart';import 'package:flutter/widgets.dart';import 'package:liqkit_ui/examples.dart';Widget sheetCompactActionBuilder(BuildContext context) {  return const SnippetFrame(child: SheetCompactActionExample());}

Custom Content

// ignore_for_file: file_namesimport 'package:docs_snippets/src/snippet_frame.dart';import 'package:flutter/widgets.dart';import 'package:liqkit_ui/examples.dart';Widget sheetCustomContentBuilder(BuildContext context) {  return const SnippetFrame(child: SheetCustomContentExample());}

Non Dismissible

// ignore_for_file: file_namesimport 'package:docs_snippets/src/snippet_frame.dart';import 'package:flutter/widgets.dart';import 'package:liqkit_ui/examples.dart';Widget sheetNonDismissibleBuilder(BuildContext context) {  return const SnippetFrame(child: SheetNonDismissibleExample());}

Destructive Action

// ignore_for_file: file_namesimport 'package:docs_snippets/src/snippet_frame.dart';import 'package:flutter/widgets.dart';import 'package:liqkit_ui/examples.dart';Widget sheetDestructiveActionBuilder(BuildContext context) {  return const SnippetFrame(child: SheetDestructiveActionExample());}