Guides
Creating a Widget

Creating a widget

Understanding styling in Jolt

In order to provide the most flexibility for developers, Jolt implements a consistent styling system for all widgets.

Each widget file has a corresponding style file, which defines the properties that can be modified for that widget.

Each style must implement the Style class, which allows styles to be merged. This is important because there are four places a style might be used:

  • The widget itself will define a default style, if nothing else is provided by the user, this is what is used.
  • The user can override the style in the WidgetTheme. This is useful for making changes across the whole app. For example setting the border radius for every Button.
  • A DefaultStyle widget might pass a style to all children in the tree. This works similar to DefaultTextStyle in Material.
  • A Style can be passed directly to the widget, this will override all other styles.

The style hierarchy

In order of application:

  1. Default widget style
  2. Style from widget theme
  3. Passed by DefaultStyle widget
  4. Passed directly to widget

After merging all styles, the widget will know the final appearance and behaviour it needs.

Creating a new widget

If you are creating a new publicly accessible widget please do the following:

Determine the appropriate location

All widgets should have their own folder, somewhere under lib/src/widgets/category, where category is one of the following:

  • Interaction (Buttons, Form Fields, etc)
  • Layout (Cards, Grids, etc)
  • Symbols (Icons, Text, etc)
  • Overlays (Dialogs, tooltips, etc)
  • Animation (Indicators, effects, etc)

Create both a widget and style file

Each widget needs two files:

  • widget.dart - The widget itself
  • widget.style.dart - Defines the modifiable properties of the widget

Replace widget appropriately with the name of your widget.

Implement the style file

Always use freezed (opens in a new tab) when making a new style. It will give you a copyWith method, as well as equality.

You will need to create the merge method yourself, when you implement the Style class.

my_widget_style.dart
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:jolt/jolt.dart';
 
part 'my_widget_style.freezed.dart';
 
///
@freezed
class MyWidgetStyle with _$MyWidgetStyle implements Style<MyWidgetStyle> {
  /// Defines the style of a [Widget] widget
  const factory MyWidgetStyle({
    /// Make sure to document
    EdgeInsetsGeometry? padding,
    /// Each available property
    Color? color,
    /// In your style class
    bool? someOption,
  }) = _MyWidgetStyle;
 
  const MyWidgetStyle._();
 
  @override
  MyWidgetStyle merge(WidgetStyle? style) {
    return copyWith(
      padding: padding ?? style?.padding,
      color: color ?? style?.color,
      someOption: someOption ?? style?.someOption,
    );
  }
}

Semantics