Practical, copy-paste patterns for using Garnish in real Flutter UIs.
import 'package:flutter/material.dart';
import 'package:garnish/garnish.dart';Always-readable text, whatever the background:
class AdaptiveLabel extends StatelessWidget {
const AdaptiveLabel(this.text, {required this.background, super.key});
final String text;
final Color background;
@override
Widget build(BuildContext context) {
final foreground = Garnish.contrastingColor(Colors.black, against: background);
return Container(
color: background,
padding: const EdgeInsets.all(12),
child: Text(
text,
style: TextStyle(
color: foreground,
fontWeight: foreground.recommendedFontWeight(against: background),
),
),
);
}
}Foreground color and weight both derive from the button color:
class GarnishButton extends StatelessWidget {
const GarnishButton({required this.label, required this.color, this.onPressed, super.key});
final String label;
final Color color;
final VoidCallback? onPressed;
@override
Widget build(BuildContext context) {
final fg = Garnish.contrastingColor(Colors.white, against: color);
return FilledButton(
onPressed: onPressed,
style: FilledButton.styleFrom(backgroundColor: color, foregroundColor: fg),
child: Text(
label,
style: TextStyle(fontWeight: fg.recommendedFontWeight(against: color)),
),
);
}
}Show live AA/AAA status for a foreground/background pair:
class ContrastBadge extends StatelessWidget {
const ContrastBadge({required this.foreground, required this.background, super.key});
final Color foreground;
final Color background;
@override
Widget build(BuildContext context) {
final ratio = foreground.contrastRatio(background);
final (label, color) = switch (ratio) {
>= GarnishMath.wcagAAAThreshold => ('AAA · ${ratio.toStringAsFixed(1)}:1', Colors.green),
>= GarnishMath.wcagAAThreshold => ('AA · ${ratio.toStringAsFixed(1)}:1', Colors.teal),
_ => ('Fail · ${ratio.toStringAsFixed(1)}:1', Colors.red),
};
return Chip(label: Text(label), backgroundColor: color.withValues(alpha: 0.15));
}
}Map any string to a stable, readable chip color:
Color colorForLabel(String label) {
final hue = (label.hashCode % 360).abs().toDouble();
return HSVColor.fromAHSV(1, hue, 0.6, 0.8).toColor();
}
Widget tag(String label) {
final bg = colorForLabel(label);
return Chip(
backgroundColor: bg,
label: Text(label, style: TextStyle(color: bg.contrastingShade())),
);
}Turn one brand color into a harmonious gradient:
import 'package:garnish/garnish_expansion.dart';
Widget brandGradient(Color brand, {Widget? child}) {
final colors = GarnishColorExpansion.expandToGradientMesh(brand, size: 4);
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: colors,
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
child: child,
);
}Nudge a color toward the current theme's brightness:
Color tintForTheme(Color base, Brightness brightness) {
final delta = brightness == Brightness.dark ? -0.2 : 0.1;
return GarnishColor.adjustBrightness(base, by: delta);
}AppBar garnishAppBar(String title, Color background) {
final fg = Garnish.contrastingColor(Colors.white, against: background);
return AppBar(
backgroundColor: background,
foregroundColor: fg,
title: Text(
title,
style: TextStyle(fontWeight: fg.recommendedFontWeight(against: background)),
),
);
}List<String> auditPalette(Map<String, (Color fg, Color bg)> pairs) {
return [
for (final entry in pairs.entries)
if (!entry.value.$1.meetsWCAGAA(entry.value.$2))
'${entry.key}: only ${entry.value.$1.contrastRatio(entry.value.$2).toStringAsFixed(1)}:1',
];
}