Skip to content
HyperUI for Flutter requires the Style package — this site itself ships no pub package.

Dropdowns

Ported from HyperUI’s Dropdowns — see Attribution. hyperui’s own static gallery capture for this pattern component type shows the dropdown menu already open (no interactive open/close state to port — see docs/agents/parity-pipeline.md’s hazard legend) — all 3 variants are a single static state, fully parity-green.

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 _chevronDownSvg =
'''<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="m19.5 8.25-7.5 7.5-7.5-7.5"/></svg>''';
class Dropdown1Example extends StatelessWidget {
const Dropdown1Example({super.key});
@override
Widget build(BuildContext context) {
return Style(
'mx-auto flex max-w-sm justify-center p-6',
child: Style(
'relative inline-flex',
children: [
Style(
'inline-flex divide-x divide-gray-300 overflow-hidden rounded border border-gray-300 bg-white shadow-sm',
children: [
Style(
'px-3 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-50 hover:text-gray-900 focus:relative',
cursor: SystemMouseCursors.click,
child: const Text('Product'),
),
Style(
'px-3 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-50 hover:text-gray-900 focus:relative',
cursor: SystemMouseCursors.click,
child: Style(
'size-4',
child: const CurrentColorIcon(_chevronDownSvg),
),
),
],
),
Style(
'absolute end-0 top-12 z-auto w-56 overflow-hidden rounded border border-gray-300 bg-white shadow-sm',
children: [
Style(
'block px-3 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-50 hover:text-gray-900',
cursor: SystemMouseCursors.click,
child: const Text('Storefront'),
),
Style(
'block px-3 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-50 hover:text-gray-900',
cursor: SystemMouseCursors.click,
child: const Text('Warehouse'),
),
Style(
'block px-3 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-50 hover:text-gray-900',
cursor: SystemMouseCursors.click,
child: const Text('Stock'),
),
Style(
'block w-full px-3 py-2 text-sm font-medium text-red-700 transition-colors hover:bg-red-50 ltr:text-left rtl:text-right',
cursor: SystemMouseCursors.click,
child: const Text('Delete'),
),
],
),
],
),
);
}
}
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 _chevronDownSvg =
'''<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="m19.5 8.25-7.5 7.5-7.5-7.5"/></svg>''';
class Dropdown2Example extends StatelessWidget {
const Dropdown2Example({super.key});
@override
Widget build(BuildContext context) {
return Style(
'mx-auto flex max-w-sm justify-center p-6',
child: Style(
'relative inline-flex',
children: [
Style(
'inline-flex divide-x divide-gray-300 overflow-hidden rounded border border-gray-300 bg-white shadow-sm',
children: [
Style(
'px-3 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-50 hover:text-gray-900 focus:relative',
cursor: SystemMouseCursors.click,
child: const Text('Product'),
),
Style(
'px-3 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-50 hover:text-gray-900 focus:relative',
cursor: SystemMouseCursors.click,
child: Style(
'size-4',
child: const CurrentColorIcon(_chevronDownSvg),
),
),
],
),
Style(
'absolute end-0 top-12 z-auto w-56 divide-y divide-gray-200 overflow-hidden rounded border border-gray-300 bg-white shadow-sm',
children: [
Style.empty(
children: [
Style(
'block px-3 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-50 hover:text-gray-900',
cursor: SystemMouseCursors.click,
child: const Text('Storefront'),
),
Style(
'block px-3 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-50 hover:text-gray-900',
cursor: SystemMouseCursors.click,
child: const Text('Warehouse'),
),
Style(
'block px-3 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-50 hover:text-gray-900',
cursor: SystemMouseCursors.click,
child: const Text('Stock'),
),
],
),
Style(
'block w-full px-3 py-2 text-sm font-medium text-red-700 transition-colors hover:bg-red-50 ltr:text-left rtl:text-right',
cursor: SystemMouseCursors.click,
child: const Text('Delete'),
),
],
),
],
),
);
}
}
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 _chevronDownSvg =
'''<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="m19.5 8.25-7.5 7.5-7.5-7.5"/></svg>''';
class Dropdown3Example extends StatelessWidget {
const Dropdown3Example({super.key});
@override
Widget build(BuildContext context) {
return Style(
'mx-auto flex max-w-sm justify-center p-6',
child: Style(
'relative inline-flex',
children: [
Style(
'inline-flex divide-x divide-gray-300 overflow-hidden rounded border border-gray-300 bg-white shadow-sm',
children: [
Style(
'px-3 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-50 hover:text-gray-900 focus:relative',
cursor: SystemMouseCursors.click,
child: const Text('Product'),
),
Style(
'px-3 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-50 hover:text-gray-900 focus:relative',
cursor: SystemMouseCursors.click,
child: Style(
'size-4',
child: const CurrentColorIcon(_chevronDownSvg),
),
),
],
),
Style(
'absolute end-0 top-12 z-auto w-56 divide-y divide-gray-200 overflow-hidden rounded border border-gray-300 bg-white shadow-sm',
children: [
Style.empty(
children: [
const Style(
'block px-3 py-2 text-sm text-gray-500',
child: Text('General'),
),
Style(
'block px-3 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-50 hover:text-gray-900',
cursor: SystemMouseCursors.click,
child: const Text('Storefront'),
),
Style(
'block px-3 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-50 hover:text-gray-900',
cursor: SystemMouseCursors.click,
child: const Text('Warehouse'),
),
Style(
'block px-3 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-50 hover:text-gray-900',
cursor: SystemMouseCursors.click,
child: const Text('Stock'),
),
],
),
Style.empty(
children: [
const Style(
'block px-3 py-2 text-sm text-gray-500',
child: Text('Actions'),
),
Style(
'block w-full px-3 py-2 text-sm font-medium text-red-700 transition-colors hover:bg-red-50 ltr:text-left rtl:text-right',
cursor: SystemMouseCursors.click,
child: const Text('Delete'),
),
],
),
],
),
],
),
);
}
}