Themes

Forui themes allows you to customize the look and feel of your Flutter application. Our theming solution is designed to help you get started quickly while offering powerful and flexible customization options.

Predefined Themes

Forui does not manage the theme brightness (light or dark) automatically. You need to specify the theme explicitly in FTheme(...).

main.dart
@override
Widget build(BuildContext context) => FTheme(
      data: FThemes.zinc.light, // or FThemes.zinc.dark
      child: const FScaffold(...),
    );

Forui provides a set of predefined themes that you can use out of the box. The color schemes are heavily inspired by shadcn/ui themes.

ThemeLight AccessorDark Accessor

Zinc

FThemes.zinc.lightFThemes.zinc.dark

Slate

FThemes.slate.lightFThemes.slate.dark

Red

FThemes.red.lightFThemes.red.dark

Rose

FThemes.rose.lightFThemes.rose.dark

Orange

FThemes.orange.lightFThemes.orange.dark

Green

FThemes.green.lightFThemes.green.dark

Blue

FThemes.blue.lightFThemes.blue.dark

Yellow

FThemes.yellow.lightFThemes.yellow.dark

Violet

FThemes.violet.lightFThemes.violet.dark

Usage

FTheme uses inherited widgets to provide the FThemeData to all widgets in the subtree. Forui provides an extension on BuildContext which allows for direct access to FThemeData through context.theme.

@override
Widget build(BuildContext context) {
  final theme = context.theme; // FThemeData
  final colorScheme = context.theme.colorScheme; // FColorScheme
  final typography = context.theme.typography; // FTypography
  final style = context.theme.style; // FStyle
 
  return const Placeholder();
}

A high level overview of the theme data structure is as follows:

  • FThemeData contains FColorScheme, FTypography, FStyle, and widget styles (eg. FCardStyle).
  • FColorScheme contains the color scheme (eg. background, foreground, and primary).
  • FTypography contains the defaultFontFamily and various TextStyles.
  • FStyle contains other miscellaneous styling options (eg. borderRadius).

A more detailed explanation of each class can be found in the Class Diagram section.

Customize Themes

It’s recommended to use the predefined themes as a starting point and customize them with the inhert(...) constructor and copyWith(...) method to suit your needs.

main.dart
@override
Widget build(BuildContext context) {
  final theme = FThemeData.inherit(
    colorScheme: FThemes.zinc.light.colorScheme.copyWith(
      primary: const Color(0xFF0D47A1), // dark blue
      primaryForeground: const Color(0xFFFFFFFF), // white
    ),
    typography: FThemes.zinc.light.typography.copyWith(
      defaultFontFamily: 'Roboto',
    ).scale(sizeScalar: 0.8),
    style: FThemes.zinc.light.style.copyWith(
      borderRadius: BorderRadius.zero,
    ),
  );
 
  return FTheme(
    data: theme.copyWith(
      cardStyle: theme.cardStyle.copyWith(
        decoration: theme.cardStyle.decoration.copyWith(
          borderRadius: const BorderRadius.all(Radius.circular(8)),
        ),
      ),
    ),
    child: const FScaffold(...),
  );
}

The example above uses FThemes.zinc.light theme as a starting point and customizes the following:

  • Update the primary and primaryForeground colors.
  • Change the default font family to Roboto and scale the font size by 2.
  • Remove the borderRadius through the style.
  • Although we removed the borderRadius for all widgets, override the borderRadius to 8 for the FCard() widget.
⚠️

It’s important to use the newly created theme instead of FThemes.zinc.light. This allows colorScheme, typography, and style to be inherited by widget-specific themes.

return FTheme(
  data: theme.copyWith(
    cardStyle: theme.cardStyle.copyWith(
      decoration: theme.cardStyle.decoration.copyWith(
        borderRadius: const BorderRadius.all(Radius.circular(8)),
      ),
    ),
  ),
  child: const FScaffold(...),
);

While the example may seem overwhelming, most use cases will only require customizations to the FColorScheme, FTypography, and FStyle class. Sensible defaults for each Forui widget will be automatically inherited.

Class Diagram

Color Scheme

The FColorScheme class contains the color scheme for the theme. This usually consist of a set of colors with its corresponding foreground color (eg. primary and primaryForeground).

In most cases, the color will be used as the background color, and the foreground color will be used as the text/icon color.

@override
Widget build(BuildContext context) {
  final colorScheme = context.theme.colorScheme;
  final typography = context.theme.typography;
 
  return ColoredBox(
    color: colorScheme.primary,
    child: Text(
      'Hello World!',
      style: typography.xs.copyWith(
          color: colorScheme.primaryForeground
      ),
    ),
  );
}

Typography

The FTypography class contains the typography settings for the theme. This includes the default font family and various TextStyles for different use cases.

The TextStyles stored in FTypography are based on Tailwind CSS Font Size. For instance, FTypography.sm is closely related to text-sm in Tailwind CSS.

It is recommended to use the copyWith(...) to apply colors and other styles as the TextStyles stored only contain the fontSize and height properties.

@override
Widget build(BuildContext context) {
  final colorScheme = context.theme.colorScheme;
  final typography = context.theme.typography;
 
  return Text(
    'Hello World!',
    style: typography.xs.copyWith(
      color: colorScheme.primaryForeground,
      fontWeight: FontWeight.bold,
      fontStyle: FontStyle.italic,
    ),
  );
}

Custom Font Family

To change the default font family, use the copyWith(...) method to apply the new font family. As some fonts may have different sizes, the scale(...) method is provided to quickly scale all the font sizes.

main.dart
@override
Widget build(BuildContext context) => FTheme(
      data: FThemes.zinc.light.copyWith(
        typography: FThemes.zinc.light.typography.copyWith(
          defaultFontFamily: 'Roboto',
        ).scale(sizeScalar: 0.8),
      ),
      child: const FScaffold(...),
    );

Style

The FStyle class contains other miscellaneous styling options for the theme.

@override
Widget build(BuildContext context) {
  final colorScheme = context.theme.colorScheme;
  final style = context.theme.style;
 
  return DecoratedBox(
    decoration: BoxDecoration(
      border: Border.all(
        color: colorScheme.border,
        width: style.borderWidth,
      ),
      borderRadius: style.borderRadius,
      color: colorScheme.primary,
    ),
    child: const Placeholder(),
  );
}

Override Individual Widgets

In certain cases, you may want to override the theme for a specific widget. This can be easily achieved by using the style(...) parameter.

In the example below, styles are only overridden for this specific FCard widget. FCard widgets that are used elsewhere will still inherit from theme data.

main.dart
@override
Widget build(BuildContext context) {
  final theme = context.theme;
 
  return FCard(
    title: 'Notification',
    subtitle: 'You have 3 new messages',
    style: theme.cardStyle.copyWith(
      decoration: theme.cardStyle.decoration.copyWith(
        borderRadius: BorderRadius.zero, // Remove border radius.
      ),
    ),
  );
}