Carts
Ported from HyperUI’s Carts — see Attribution.
Includes a dark: variant — toggle the site theme (top right) to preview it.
class CurrentColorIcon extends StatelessWidget implements StyleReplacedElementWrapper { const CurrentColorIcon(this.svg, {super.key});
final String svg;
@override Widget build(BuildContext context) { final color = IconTheme.of(context).color ?? const Color(0xFF000000); return SvgPicture.string(svg, theme: SvgTheme(currentColor: color)); }}
const _photoUrl = 'https://images.unsplash.com/photo-1618354691373-d851c5c3a990?auto=format&fit=crop&q=80&w=1160';
const _closeSvg = '''<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/></svg>''';
class Carts1Example extends StatelessWidget { const Carts1Example({super.key});
@override Widget build(BuildContext context) { return Style( 'flex justify-end p-6', child: Style( 'relative w-screen max-w-sm border border-gray-300 bg-gray-100 px-4 py-8 sm:px-6 lg:px-8 dark:border-gray-600 dark:bg-gray-800', children: [ Style( 'absolute inset-e-4 top-4 text-gray-600 transition hover:scale-110 dark:text-gray-300', cursor: SystemMouseCursors.click, children: [ const Style('sr-only', child: Text('Close cart')), const Style('size-5', child: CurrentColorIcon(_closeSvg)), ], ), Style( 'mt-4 space-y-6', children: [ Style( 'space-y-4', children: [ Style( 'flex items-center gap-4', children: [ Style( 'size-16 rounded-sm object-cover', child: Image.network(_photoUrl, fit: BoxFit.cover), ), Style.empty( children: [ const Style( 'text-sm text-gray-900 dark:text-white', child: Text('Basic Tee 6-Pack'), ), Style( 'mt-0.5 space-y-px text-[10px] text-gray-600 dark:text-gray-300', children: [ Style.empty( child: Row( mainAxisSize: MainAxisSize.min, children: [ const Style( 'inline', child: Text('Size: '), ), const Style('inline', child: Text('XXS')), ], ), ), Style.empty( child: Row( mainAxisSize: MainAxisSize.min, children: [ const Style( 'inline', child: Text('Color: '), ), const Style('inline', child: Text('White')), ], ), ), ], ), ], ), ], ), Style( 'flex items-center gap-4', children: [ Style( 'size-16 rounded-sm object-cover', child: Image.network(_photoUrl, fit: BoxFit.cover), ), Style.empty( children: [ const Style( 'text-sm text-gray-900 dark:text-white', child: Text('Basic Tee 6-Pack'), ), Style( 'mt-0.5 space-y-px text-[10px] text-gray-600 dark:text-gray-300', children: [ Style.empty( child: Row( mainAxisSize: MainAxisSize.min, children: [ const Style( 'inline', child: Text('Size: '), ), const Style('inline', child: Text('XXS')), ], ), ), Style.empty( child: Row( mainAxisSize: MainAxisSize.min, children: [ const Style( 'inline', child: Text('Color: '), ), const Style('inline', child: Text('White')), ], ), ), ], ), ], ), ], ), Style( 'flex items-center gap-4', children: [ Style( 'size-16 rounded-sm object-cover', child: Image.network(_photoUrl, fit: BoxFit.cover), ), Style.empty( children: [ const Style( 'text-sm text-gray-900 dark:text-white', child: Text('Basic Tee 6-Pack'), ), Style( 'mt-0.5 space-y-px text-[10px] text-gray-600 dark:text-gray-300', children: [ Style.empty( child: Row( mainAxisSize: MainAxisSize.min, children: [ const Style( 'inline', child: Text('Size: '), ), const Style('inline', child: Text('XXS')), ], ), ), Style.empty( child: Row( mainAxisSize: MainAxisSize.min, children: [ const Style( 'inline', child: Text('Color: '), ), const Style('inline', child: Text('White')), ], ), ), ], ), ], ), ], ), ], ), Style( 'space-y-4 text-center', children: [ Style( 'block rounded-sm border border-gray-300 bg-gray-50 px-5 py-3 text-sm text-gray-700 transition-colors hover:text-gray-900 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200 dark:hover:text-white', cursor: SystemMouseCursors.click, child: const Text('View my cart (2)'), ), Style( 'block rounded-sm border border-blue-600 bg-blue-600 px-5 py-3 text-sm font-semibold text-white transition-colors hover:border-blue-700 hover:bg-blue-700 dark:border-blue-300 dark:bg-blue-300 dark:text-gray-900 dark:hover:border-blue-200 dark:hover:bg-blue-200', cursor: SystemMouseCursors.click, child: const Text('Checkout'), ), Style( 'inline-block text-sm text-gray-600 underline underline-offset-4 transition-colors hover:text-gray-700 dark:text-gray-300 dark:hover:text-gray-200', cursor: SystemMouseCursors.click, child: const Text('Continue shopping'), ), ], ), ], ), ], ), ); }}<div class="relative w-screen max-w-sm border border-gray-300 bg-gray-100 px-4 py-8 sm:px-6 lg:px-8" aria-modal="true" role="dialog" aria-label="Shopping cart" tabindex="-1"> <button class="absolute inset-e-4 top-4 text-gray-600 transition hover:scale-110"> <span class="sr-only">Close cart</span>
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-5" > <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" /> </svg> </button>
<div class="mt-4 space-y-6"> <ul class="space-y-4"> <li class="flex items-center gap-4"> <img src="https://images.unsplash.com/photo-1618354691373-d851c5c3a990?auto=format&fit=crop&q=80&w=1160" alt="" class="size-16 rounded-sm object-cover" />
<div> <h3 class="text-sm text-gray-900">Basic Tee 6-Pack</h3>
<dl class="mt-0.5 space-y-px text-[10px] text-gray-600"> <div> <dt class="inline">Size:</dt> <dd class="inline">XXS</dd> </div>
<div> <dt class="inline">Color:</dt> <dd class="inline">White</dd> </div> </dl> </div> </li>
<li class="flex items-center gap-4"> <img src="https://images.unsplash.com/photo-1618354691373-d851c5c3a990?auto=format&fit=crop&q=80&w=1160" alt="" class="size-16 rounded-sm object-cover" />
<div> <h3 class="text-sm text-gray-900">Basic Tee 6-Pack</h3>
<dl class="mt-0.5 space-y-px text-[10px] text-gray-600"> <div> <dt class="inline">Size:</dt> <dd class="inline">XXS</dd> </div>
<div> <dt class="inline">Color:</dt> <dd class="inline">White</dd> </div> </dl> </div> </li>
<li class="flex items-center gap-4"> <img src="https://images.unsplash.com/photo-1618354691373-d851c5c3a990?auto=format&fit=crop&q=80&w=1160" alt="" class="size-16 rounded-sm object-cover" />
<div> <h3 class="text-sm text-gray-900">Basic Tee 6-Pack</h3>
<dl class="mt-0.5 space-y-px text-[10px] text-gray-600"> <div> <dt class="inline">Size:</dt> <dd class="inline">XXS</dd> </div>
<div> <dt class="inline">Color:</dt> <dd class="inline">White</dd> </div> </dl> </div> </li> </ul>
<div class="space-y-4 text-center"> <a href="#" class="block rounded-sm border border-gray-300 bg-gray-50 px-5 py-3 text-sm text-gray-700 transition-colors hover:text-gray-900" > View my cart (2) </a>
<a href="#" class="block rounded-sm border border-blue-600 bg-blue-600 px-5 py-3 text-sm font-semibold text-white transition-colors hover:border-blue-700 hover:bg-blue-700" > Checkout </a>
<a href="#" class="inline-block text-sm text-gray-600 underline underline-offset-4 transition-colors hover:text-gray-700" > Continue shopping </a> </div> </div></div>Popup with actions
Section titled “Popup with actions”Includes a dark: variant — toggle the site theme (top right) to preview it.
class CurrentColorIcon extends StatelessWidget implements StyleReplacedElementWrapper { const CurrentColorIcon(this.svg, {super.key});
final String svg;
@override Widget build(BuildContext context) { final color = IconTheme.of(context).color ?? const Color(0xFF000000); return SvgPicture.string(svg, theme: SvgTheme(currentColor: color)); }}
const _photoUrl = 'https://images.unsplash.com/photo-1618354691373-d851c5c3a990?auto=format&fit=crop&q=80&w=1160';
const _closeSvg = '''<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/></svg>''';
const _removeSvg = '''<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0"/></svg>''';
class _QtyField extends StatelessWidget implements StyleReplacedElementWrapper { const _QtyField({required this.initialValue});
final String initialValue;
@override Widget build(BuildContext context) => _buildQtyField(context, initialValue: initialValue);}
Widget _buildQtyField(BuildContext context, {required String initialValue}) { final isDark = Theme.of(context).brightness == Brightness.dark; const fontSize = 12.0; const lineHeight = 16.0; const vPad = (32 - 2 - lineHeight) / 2; final baseStyle = Theme.of(context).textTheme.bodyLarge ?? const TextStyle(); return Theme( data: Theme.of(context).copyWith(visualDensity: VisualDensity.standard), child: TextFormField( initialValue: initialValue, keyboardType: TextInputType.number, textAlign: TextAlign.center, style: baseStyle.copyWith( fontSize: fontSize, height: lineHeight / fontSize, color: isDark ? tailwindColors['gray']![200] : tailwindColors['gray']![700], letterSpacing: 0, ), decoration: InputDecoration( isDense: true, contentPadding: const EdgeInsets.symmetric(vertical: vPad), border: InputBorder.none, ), ), );}
class Carts2Example extends StatelessWidget { const Carts2Example({super.key});
@override Widget build(BuildContext context) { return Style( 'flex justify-end p-6', child: Style( 'relative w-screen max-w-sm border border-gray-300 bg-gray-100 px-4 py-8 sm:px-6 lg:px-8 dark:border-gray-600 dark:bg-gray-800', children: [ Style( 'absolute inset-e-4 top-4 text-gray-600 transition hover:scale-110 dark:text-gray-300', cursor: SystemMouseCursors.click, children: [ const Style('sr-only', child: Text('Close cart')), const Style('size-5', child: CurrentColorIcon(_closeSvg)), ], ), Style( 'mt-4 space-y-6', children: [ Style( 'space-y-4', children: [ Style( 'flex items-center gap-4', children: [ Style( 'size-16 rounded-sm object-cover', child: Image.network(_photoUrl, fit: BoxFit.cover), ), Style.empty( children: [ const Style( 'text-sm text-gray-900 dark:text-white', child: Text('Basic Tee 6-Pack'), ), Style( 'mt-0.5 space-y-px text-[10px] text-gray-600 dark:text-gray-300', children: [ Style.empty( child: Row( mainAxisSize: MainAxisSize.min, children: [ const Style( 'inline', child: Text('Size: '), ), const Style('inline', child: Text('XXS')), ], ), ), Style.empty( child: Row( mainAxisSize: MainAxisSize.min, children: [ const Style( 'inline', child: Text('Color: '), ), const Style('inline', child: Text('White')), ], ), ), ], ), ], ), Style( 'flex flex-1 items-center justify-end gap-2', children: [ Style.empty( children: [ const Style('sr-only', child: Text('Quantity')), Style( 'h-8 w-12 rounded-sm border-gray-300 bg-white p-0 text-center text-xs text-gray-700 [-moz-appearance:textfield] focus:outline-hidden dark:border-gray-600 dark:bg-gray-900 dark:text-gray-200 [&::-webkit-inner-spin-button]:m-0 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:m-0 [&::-webkit-outer-spin-button]:appearance-none', child: const _QtyField(initialValue: '1'), ), ], ), Style( 'text-gray-600 transition hover:text-red-600 dark:text-gray-300 dark:hover:text-red-300', cursor: SystemMouseCursors.click, children: [ const Style( 'sr-only', child: Text('Remove item'), ), const Style( 'size-4', child: CurrentColorIcon(_removeSvg), ), ], ), ], ), ], ), Style( 'flex items-center gap-4', children: [ Style( 'size-16 rounded-sm object-cover', child: Image.network(_photoUrl, fit: BoxFit.cover), ), Style.empty( children: [ const Style( 'text-sm text-gray-900 dark:text-white', child: Text('Basic Tee 6-Pack'), ), Style( 'mt-0.5 space-y-px text-[10px] text-gray-600 dark:text-gray-300', children: [ Style.empty( child: Row( mainAxisSize: MainAxisSize.min, children: [ const Style( 'inline', child: Text('Size: '), ), const Style('inline', child: Text('XXS')), ], ), ), Style.empty( child: Row( mainAxisSize: MainAxisSize.min, children: [ const Style( 'inline', child: Text('Color: '), ), const Style('inline', child: Text('White')), ], ), ), ], ), ], ), Style( 'flex flex-1 items-center justify-end gap-2', children: [ Style.empty( children: [ const Style('sr-only', child: Text('Quantity')), Style( 'h-8 w-12 rounded-sm border-gray-300 bg-white p-0 text-center text-xs text-gray-700 [-moz-appearance:textfield] focus:outline-hidden dark:border-gray-600 dark:bg-gray-900 dark:text-gray-200 [&::-webkit-inner-spin-button]:m-0 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:m-0 [&::-webkit-outer-spin-button]:appearance-none', child: const _QtyField(initialValue: '1'), ), ], ), Style( 'text-gray-600 transition hover:text-red-600 dark:text-gray-300 dark:hover:text-red-300', cursor: SystemMouseCursors.click, children: [ const Style( 'sr-only', child: Text('Remove item'), ), const Style( 'size-4', child: CurrentColorIcon(_removeSvg), ), ], ), ], ), ], ), Style( 'flex items-center gap-4', children: [ Style( 'size-16 rounded-sm object-cover', child: Image.network(_photoUrl, fit: BoxFit.cover), ), Style.empty( children: [ const Style( 'text-sm text-gray-900 dark:text-white', child: Text('Basic Tee 6-Pack'), ), Style( 'mt-0.5 space-y-px text-[10px] text-gray-600 dark:text-gray-300', children: [ Style.empty( child: Row( mainAxisSize: MainAxisSize.min, children: [ const Style( 'inline', child: Text('Size: '), ), const Style('inline', child: Text('XXS')), ], ), ), Style.empty( child: Row( mainAxisSize: MainAxisSize.min, children: [ const Style( 'inline', child: Text('Color: '), ), const Style('inline', child: Text('White')), ], ), ), ], ), ], ), Style( 'flex flex-1 items-center justify-end gap-2', children: [ Style.empty( children: [ const Style('sr-only', child: Text('Quantity')), Style( 'h-8 w-12 rounded-sm border-gray-300 bg-white p-0 text-center text-xs text-gray-700 [-moz-appearance:textfield] focus:outline-hidden dark:border-gray-600 dark:bg-gray-900 dark:text-gray-200 [&::-webkit-inner-spin-button]:m-0 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:m-0 [&::-webkit-outer-spin-button]:appearance-none', child: const _QtyField(initialValue: '2'), ), ], ), Style( 'text-gray-600 transition hover:text-red-600 dark:text-gray-300 dark:hover:text-red-300', cursor: SystemMouseCursors.click, children: [ const Style( 'sr-only', child: Text('Remove item'), ), const Style( 'size-4', child: CurrentColorIcon(_removeSvg), ), ], ), ], ), ], ), ], ), Style( 'space-y-4 text-center', children: [ Style( 'block rounded-sm border border-gray-300 bg-gray-50 px-5 py-3 text-sm text-gray-700 transition-colors hover:text-gray-900 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200 dark:hover:text-white', cursor: SystemMouseCursors.click, child: const Text('View my cart (2)'), ), Style( 'block rounded-sm border border-blue-600 bg-blue-600 px-5 py-3 text-sm font-semibold text-white transition-colors hover:border-blue-700 hover:bg-blue-700 dark:border-blue-300 dark:bg-blue-300 dark:text-gray-900 dark:hover:border-blue-200 dark:hover:bg-blue-200', cursor: SystemMouseCursors.click, child: const Text('Checkout'), ), Style( 'inline-block text-sm text-gray-600 underline underline-offset-4 transition-colors hover:text-gray-700 dark:text-gray-300 dark:hover:text-gray-200', cursor: SystemMouseCursors.click, child: const Text('Continue shopping'), ), ], ), ], ), ], ), ); }}<div class="relative w-screen max-w-sm border border-gray-300 bg-gray-100 px-4 py-8 sm:px-6 lg:px-8" aria-modal="true" role="dialog" aria-label="Shopping cart" tabindex="-1"> <button class="absolute inset-e-4 top-4 text-gray-600 transition hover:scale-110"> <span class="sr-only">Close cart</span>
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-5" > <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" /> </svg> </button>
<div class="mt-4 space-y-6"> <ul class="space-y-4"> <li class="flex items-center gap-4"> <img src="https://images.unsplash.com/photo-1618354691373-d851c5c3a990?auto=format&fit=crop&q=80&w=1160" alt="" class="size-16 rounded-sm object-cover" />
<div> <h3 class="text-sm text-gray-900">Basic Tee 6-Pack</h3>
<dl class="mt-0.5 space-y-px text-[10px] text-gray-600"> <div> <dt class="inline">Size:</dt> <dd class="inline">XXS</dd> </div>
<div> <dt class="inline">Color:</dt> <dd class="inline">White</dd> </div> </dl> </div>
<div class="flex flex-1 items-center justify-end gap-2"> <form> <label for="Line1Qty" class="sr-only"> Quantity </label>
<input type="number" min="1" value="1" id="Line1Qty" class="h-8 w-12 rounded-sm border-gray-300 bg-white p-0 text-center text-xs text-gray-700 [-moz-appearance:textfield] focus:outline-hidden [&::-webkit-inner-spin-button]:m-0 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:m-0 [&::-webkit-outer-spin-button]:appearance-none" /> </form>
<button class="text-gray-600 transition hover:text-red-600"> <span class="sr-only">Remove item</span>
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4" > <path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" /> </svg> </button> </div> </li>
<li class="flex items-center gap-4"> <img src="https://images.unsplash.com/photo-1618354691373-d851c5c3a990?auto=format&fit=crop&q=80&w=1160" alt="" class="size-16 rounded-sm object-cover" />
<div> <h3 class="text-sm text-gray-900">Basic Tee 6-Pack</h3>
<dl class="mt-0.5 space-y-px text-[10px] text-gray-600"> <div> <dt class="inline">Size:</dt> <dd class="inline">XXS</dd> </div>
<div> <dt class="inline">Color:</dt> <dd class="inline">White</dd> </div> </dl> </div>
<div class="flex flex-1 items-center justify-end gap-2"> <form> <label for="Line2Qty" class="sr-only"> Quantity </label>
<input type="number" min="1" value="1" id="Line2Qty" class="h-8 w-12 rounded-sm border-gray-300 bg-white p-0 text-center text-xs text-gray-700 [-moz-appearance:textfield] focus:outline-hidden [&::-webkit-inner-spin-button]:m-0 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:m-0 [&::-webkit-outer-spin-button]:appearance-none" /> </form>
<button class="text-gray-600 transition hover:text-red-600"> <span class="sr-only">Remove item</span>
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4" > <path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" /> </svg> </button> </div> </li>
<li class="flex items-center gap-4"> <img src="https://images.unsplash.com/photo-1618354691373-d851c5c3a990?auto=format&fit=crop&q=80&w=1160" alt="" class="size-16 rounded-sm object-cover" />
<div> <h3 class="text-sm text-gray-900">Basic Tee 6-Pack</h3>
<dl class="mt-0.5 space-y-px text-[10px] text-gray-600"> <div> <dt class="inline">Size:</dt> <dd class="inline">XXS</dd> </div>
<div> <dt class="inline">Color:</dt> <dd class="inline">White</dd> </div> </dl> </div>
<div class="flex flex-1 items-center justify-end gap-2"> <form> <label for="Line3Qty" class="sr-only"> Quantity </label>
<input type="number" min="1" value="2" id="Line3Qty" class="h-8 w-12 rounded-sm border-gray-300 bg-white p-0 text-center text-xs text-gray-700 [-moz-appearance:textfield] focus:outline-hidden [&::-webkit-inner-spin-button]:m-0 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:m-0 [&::-webkit-outer-spin-button]:appearance-none" /> </form>
<button class="text-gray-600 transition hover:text-red-600"> <span class="sr-only">Remove item</span>
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4" > <path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" /> </svg> </button> </div> </li> </ul>
<div class="space-y-4 text-center"> <a href="#" class="block rounded-sm border border-gray-300 bg-gray-50 px-5 py-3 text-sm text-gray-700 transition-colors hover:text-gray-900" > View my cart (2) </a>
<a href="#" class="block rounded-sm border border-blue-600 bg-blue-600 px-5 py-3 text-sm font-semibold text-white transition-colors hover:border-blue-700 hover:bg-blue-700" > Checkout </a>
<a href="#" class="inline-block text-sm text-gray-600 underline underline-offset-4 transition-colors hover:text-gray-700" > Continue shopping </a> </div> </div></div>Includes a dark: variant — toggle the site theme (top right) to preview it.
class CurrentColorIcon extends StatelessWidget implements StyleReplacedElementWrapper { const CurrentColorIcon(this.svg, {super.key});
final String svg;
@override Widget build(BuildContext context) { final color = IconTheme.of(context).color ?? const Color(0xFF000000); return SvgPicture.string(svg, theme: SvgTheme(currentColor: color)); }}
const _photoUrl = 'https://images.unsplash.com/photo-1618354691373-d851c5c3a990?auto=format&fit=crop&q=80&w=1160';
const _removeSvg = '''<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0"/></svg>''';
Widget _buildQtyField(BuildContext context, {required String initialValue}) { final isDark = Theme.of(context).brightness == Brightness.dark; const fontSize = 12.0; const lineHeight = 16.0; const vPad = (32 - 2 - lineHeight) / 2; final baseStyle = Theme.of(context).textTheme.bodyLarge ?? const TextStyle(); return Theme( data: Theme.of(context).copyWith(visualDensity: VisualDensity.standard), child: TextFormField( initialValue: initialValue, keyboardType: TextInputType.number, textAlign: TextAlign.center, style: baseStyle.copyWith( fontSize: fontSize, height: lineHeight / fontSize, color: isDark ? tailwindColors['gray']![200] : tailwindColors['gray']![700], letterSpacing: 0, ), decoration: InputDecoration( isDense: true, contentPadding: const EdgeInsets.symmetric(vertical: vPad), border: InputBorder.none, ), ), );}
class Carts3Example extends StatelessWidget { const Carts3Example({super.key});
@override Widget build(BuildContext context) { return Style( 'mx-auto max-w-7xl px-4 py-8 sm:px-6 lg:px-8', children: [ Style( 'space-y-4', children: [ Style( 'flex items-center gap-4', children: [ Style( 'size-16 rounded-sm object-cover', child: Image.network(_photoUrl, fit: BoxFit.cover), ), Style.empty( children: [ const Style( 'text-sm text-gray-900 dark:text-white', child: Text('Basic Tee 6-Pack'), ), Style( 'mt-0.5 space-y-px text-[10px] text-gray-600 dark:text-gray-300', children: [ Style.empty( child: Row( mainAxisSize: MainAxisSize.min, children: [ const Style('inline', child: Text('Size: ')), const Style('inline', child: Text('XXS')), ], ), ), Style.empty( child: Row( mainAxisSize: MainAxisSize.min, children: [ const Style('inline', child: Text('Color: ')), const Style('inline', child: Text('White')), ], ), ), ], ), ], ), Style( 'flex flex-1 items-center justify-end gap-2', children: [ Style.empty( children: [ const Style('sr-only', child: Text('Quantity')), Style( 'h-8 w-12 rounded-sm border-gray-300 bg-white p-0 text-center text-xs text-gray-700 [-moz-appearance:textfield] focus:outline-hidden dark:border-gray-600 dark:bg-gray-900 dark:text-gray-200 [&::-webkit-inner-spin-button]:m-0 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:m-0 [&::-webkit-outer-spin-button]:appearance-none', child: Builder( builder: (context) => _buildQtyField(context, initialValue: '1'), ), ), ], ), Style( 'text-gray-600 transition hover:text-red-600 dark:text-gray-300 dark:hover:text-red-300', cursor: SystemMouseCursors.click, children: [ const Style('sr-only', child: Text('Remove item')), const Style( 'size-4', child: CurrentColorIcon(_removeSvg), ), ], ), ], ), ], ), Style( 'flex items-center gap-4', children: [ Style( 'size-16 rounded-sm object-cover', child: Image.network(_photoUrl, fit: BoxFit.cover), ), Style.empty( children: [ const Style( 'text-sm text-gray-900 dark:text-white', child: Text('Basic Tee 6-Pack'), ), Style( 'mt-0.5 space-y-px text-[10px] text-gray-600 dark:text-gray-300', children: [ Style.empty( child: Row( mainAxisSize: MainAxisSize.min, children: [ const Style('inline', child: Text('Size: ')), const Style('inline', child: Text('XXS')), ], ), ), Style.empty( child: Row( mainAxisSize: MainAxisSize.min, children: [ const Style('inline', child: Text('Color: ')), const Style('inline', child: Text('White')), ], ), ), ], ), ], ), Style( 'flex flex-1 items-center justify-end gap-2', children: [ Style.empty( children: [ const Style('sr-only', child: Text('Quantity')), Style( 'h-8 w-12 rounded-sm border-gray-300 bg-white p-0 text-center text-xs text-gray-700 [-moz-appearance:textfield] focus:outline-hidden dark:border-gray-600 dark:bg-gray-900 dark:text-gray-200 [&::-webkit-inner-spin-button]:m-0 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:m-0 [&::-webkit-outer-spin-button]:appearance-none', child: Builder( builder: (context) => _buildQtyField(context, initialValue: '1'), ), ), ], ), Style( 'text-gray-600 transition hover:text-red-600 dark:text-gray-300 dark:hover:text-red-300', cursor: SystemMouseCursors.click, children: [ const Style('sr-only', child: Text('Remove item')), const Style( 'size-4', child: CurrentColorIcon(_removeSvg), ), ], ), ], ), ], ), Style( 'flex items-center gap-4', children: [ Style( 'size-16 rounded-sm object-cover', child: Image.network(_photoUrl, fit: BoxFit.cover), ), Style.empty( children: [ const Style( 'text-sm text-gray-900 dark:text-white', child: Text('Basic Tee 6-Pack'), ), Style( 'mt-0.5 space-y-px text-[10px] text-gray-600 dark:text-gray-300', children: [ Style.empty( child: Row( mainAxisSize: MainAxisSize.min, children: [ const Style('inline', child: Text('Size: ')), const Style('inline', child: Text('XXS')), ], ), ), Style.empty( child: Row( mainAxisSize: MainAxisSize.min, children: [ const Style('inline', child: Text('Color: ')), const Style('inline', child: Text('White')), ], ), ), ], ), ], ), Style( 'flex flex-1 items-center justify-end gap-2', children: [ Style.empty( children: [ const Style('sr-only', child: Text('Quantity')), Style( 'h-8 w-12 rounded-sm border-gray-300 bg-white p-0 text-center text-xs text-gray-700 [-moz-appearance:textfield] focus:outline-hidden dark:border-gray-600 dark:bg-gray-900 dark:text-gray-200 [&::-webkit-inner-spin-button]:m-0 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:m-0 [&::-webkit-outer-spin-button]:appearance-none', child: Builder( builder: (context) => _buildQtyField(context, initialValue: '2'), ), ), ], ), Style( 'text-gray-600 transition hover:text-red-600 dark:text-gray-300 dark:hover:text-red-300', cursor: SystemMouseCursors.click, children: [ const Style('sr-only', child: Text('Remove item')), const Style( 'size-4', child: CurrentColorIcon(_removeSvg), ), ], ), ], ), ], ), ], ), Style( 'mt-8 space-y-6 border-t border-gray-100 pt-8 dark:border-gray-800', children: [ Style( 'ml-auto max-w-sm space-y-1 text-sm text-gray-700 dark:text-gray-200', children: [ Style( 'flex justify-between', children: const [ Style.empty(child: Text('Subtotal')), Style.empty(child: Text('£250')), ], ), Style( 'flex justify-between', children: const [ Style.empty(child: Text('VAT')), Style.empty(child: Text('£25')), ], ), Style( 'flex justify-between', children: const [ Style.empty(child: Text('Discount')), Style.empty(child: Text('-£20')), ], ), Style( 'flex justify-between font-semibold', children: const [ Style.empty(child: Text('Total')), Style.empty(child: Text('£200')), ], ), ], ), Style( 'flex items-center justify-end gap-4', children: [ Style( 'block rounded-sm border border-gray-300 bg-gray-50 px-5 py-3 text-sm text-gray-700 transition-colors hover:text-gray-900 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200 dark:hover:text-white', cursor: SystemMouseCursors.click, child: const Text('View my cart (2)'), ), Style( 'block rounded-sm border border-blue-600 bg-blue-600 px-5 py-3 text-sm font-semibold text-white transition-colors hover:border-blue-700 hover:bg-blue-700 dark:border-blue-300 dark:bg-blue-300 dark:text-gray-900 dark:hover:border-blue-200 dark:hover:bg-blue-200', cursor: SystemMouseCursors.click, child: const Text('Checkout'), ), ], ), Style( 'text-right', child: Style( 'inline-block text-sm text-gray-600 underline underline-offset-4 transition-colors hover:text-gray-700 dark:text-gray-300 dark:hover:text-gray-200', cursor: SystemMouseCursors.click, child: const Text('Continue shopping'), ), ), ], ), ], ); }}<div class="mx-auto max-w-7xl px-4 py-8 sm:px-6 lg:px-8"> <ul class="space-y-4"> <li class="flex items-center gap-4"> <img src="https://images.unsplash.com/photo-1618354691373-d851c5c3a990?auto=format&fit=crop&q=80&w=1160" alt="" class="size-16 rounded-sm object-cover" />
<div> <h3 class="text-sm text-gray-900">Basic Tee 6-Pack</h3>
<dl class="mt-0.5 space-y-px text-[10px] text-gray-600"> <div> <dt class="inline">Size:</dt> <dd class="inline">XXS</dd> </div>
<div> <dt class="inline">Color:</dt> <dd class="inline">White</dd> </div> </dl> </div>
<div class="flex flex-1 items-center justify-end gap-2"> <form> <label for="Line1Qty" class="sr-only"> Quantity </label>
<input type="number" min="1" value="1" id="Line1Qty" class="h-8 w-12 rounded-sm border-gray-300 bg-white p-0 text-center text-xs text-gray-700 [-moz-appearance:textfield] focus:outline-hidden [&::-webkit-inner-spin-button]:m-0 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:m-0 [&::-webkit-outer-spin-button]:appearance-none" /> </form>
<button class="text-gray-600 transition hover:text-red-600"> <span class="sr-only">Remove item</span>
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4" > <path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" /> </svg> </button> </div> </li>
<li class="flex items-center gap-4"> <img src="https://images.unsplash.com/photo-1618354691373-d851c5c3a990?auto=format&fit=crop&q=80&w=1160" alt="" class="size-16 rounded-sm object-cover" />
<div> <h3 class="text-sm text-gray-900">Basic Tee 6-Pack</h3>
<dl class="mt-0.5 space-y-px text-[10px] text-gray-600"> <div> <dt class="inline">Size:</dt> <dd class="inline">XXS</dd> </div>
<div> <dt class="inline">Color:</dt> <dd class="inline">White</dd> </div> </dl> </div>
<div class="flex flex-1 items-center justify-end gap-2"> <form> <label for="Line2Qty" class="sr-only"> Quantity </label>
<input type="number" min="1" value="1" id="Line2Qty" class="h-8 w-12 rounded-sm border-gray-300 bg-white p-0 text-center text-xs text-gray-700 [-moz-appearance:textfield] focus:outline-hidden [&::-webkit-inner-spin-button]:m-0 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:m-0 [&::-webkit-outer-spin-button]:appearance-none" /> </form>
<button class="text-gray-600 transition hover:text-red-600"> <span class="sr-only">Remove item</span>
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4" > <path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" /> </svg> </button> </div> </li>
<li class="flex items-center gap-4"> <img src="https://images.unsplash.com/photo-1618354691373-d851c5c3a990?auto=format&fit=crop&q=80&w=1160" alt="" class="size-16 rounded-sm object-cover" />
<div> <h3 class="text-sm text-gray-900">Basic Tee 6-Pack</h3>
<dl class="mt-0.5 space-y-px text-[10px] text-gray-600"> <div> <dt class="inline">Size:</dt> <dd class="inline">XXS</dd> </div>
<div> <dt class="inline">Color:</dt> <dd class="inline">White</dd> </div> </dl> </div>
<div class="flex flex-1 items-center justify-end gap-2"> <form> <label for="Line3Qty" class="sr-only"> Quantity </label>
<input type="number" min="1" value="2" id="Line3Qty" class="h-8 w-12 rounded-sm border-gray-300 bg-white p-0 text-center text-xs text-gray-700 [-moz-appearance:textfield] focus:outline-hidden [&::-webkit-inner-spin-button]:m-0 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:m-0 [&::-webkit-outer-spin-button]:appearance-none" /> </form>
<button class="text-gray-600 transition hover:text-red-600"> <span class="sr-only">Remove item</span>
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4" > <path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" /> </svg> </button> </div> </li> </ul>
<div class="mt-8 space-y-6 border-t border-gray-100 pt-8"> <dl class="ml-auto max-w-sm space-y-1 text-sm text-gray-700"> <div class="flex justify-between"> <dt>Subtotal</dt> <dd>£250</dd> </div>
<div class="flex justify-between"> <dt>VAT</dt> <dd>£25</dd> </div>
<div class="flex justify-between"> <dt>Discount</dt> <dd>-£20</dd> </div>
<div class="flex justify-between font-semibold"> <dt>Total</dt> <dd>£200</dd> </div> </dl>
<div class="flex items-center justify-end gap-4"> <a href="#" class="block rounded-sm border border-gray-300 bg-gray-50 px-5 py-3 text-sm text-gray-700 transition-colors hover:text-gray-900" > View my cart (2) </a>
<a href="#" class="block rounded-sm border border-blue-600 bg-blue-600 px-5 py-3 text-sm font-semibold text-white transition-colors hover:border-blue-700 hover:bg-blue-700" > Checkout </a> </div>
<div class="text-right"> <a href="#" class="inline-block text-sm text-gray-600 underline underline-offset-4 transition-colors hover:text-gray-700" > Continue shopping </a> </div> </div></div>