Skip to main content

Theming

Drift provides a Material Design 3 inspired theming system.

Using Theme

Get all theme parts in one call:

func (s *myState) Build(ctx core.BuildContext) core.Widget {
_, colors, textTheme := theme.UseTheme(ctx)

return widgets.NewContainer(
widgets.TextOf("Hello", textTheme.HeadlineLarge),
).WithColor(colors.Surface).Build()
}

Individual Accessors

When you only need one part:

colors := theme.ColorsOf(ctx)
textTheme := theme.TextThemeOf(ctx)
themeData := theme.ThemeOf(ctx)

Providing Theme

Wrap your app with a Theme widget:

theme.Theme{
Data: theme.DefaultDarkTheme(), // or DefaultLightTheme()
ChildWidget: myApp,
}

Built-in Themes

Drift includes light and dark themes:

// Light theme
theme.DefaultLightTheme()

// Dark theme
theme.DefaultDarkTheme()

Color Scheme

The color scheme follows Material Design 3:

ColorPurpose
PrimaryMain brand color
OnPrimaryText/icons on primary
SecondaryAccent color
OnSecondaryText/icons on secondary
SurfaceBackground for cards, sheets
OnSurfaceText/icons on surface
BackgroundApp background
OnBackgroundText/icons on background
ErrorError states
OnErrorText/icons on error

Usage:

colors := theme.ColorsOf(ctx)

widgets.NewContainer(child).
WithColor(colors.Surface).
Build()

widgets.TextOf("Error!", rendering.TextStyle{
Color: colors.Error,
})

Text Theme

Typography follows Material Design 3:

StyleTypical Use
DisplayLargeHero text
DisplayMediumLarge headlines
DisplaySmallSection headers
HeadlineLargePage titles
HeadlineMediumSection titles
HeadlineSmallSubsection titles
TitleLargeCard titles
TitleMediumList item titles
TitleSmallCaptions
BodyLargePrimary body text
BodyMediumSecondary body text
BodySmallTertiary text
LabelLargeButton text
LabelMediumTab labels
LabelSmallChip text

Usage:

textTheme := theme.TextThemeOf(ctx)

widgets.TextOf("Welcome", textTheme.HeadlineLarge)
widgets.TextOf("Body content", textTheme.BodyMedium)

Custom Themes

Create a custom theme by building ThemeData:

myTheme := theme.ThemeData{
ColorScheme: theme.ColorScheme{
Primary: rendering.RGB(0x67, 0x50, 0xA7), // Purple
OnPrimary: rendering.ColorWhite,
Secondary: rendering.RGB(0x62, 0x5B, 0x71),
OnSecondary: rendering.ColorWhite,
Surface: rendering.RGB(0xFE, 0xF7, 0xFF),
OnSurface: rendering.RGB(0x1D, 0x1B, 0x20),
Background: rendering.ColorWhite,
OnBackground: rendering.ColorBlack,
Error: rendering.RGB(0xB3, 0x26, 0x1E),
OnError: rendering.ColorWhite,
},
TextTheme: theme.DefaultTextTheme(),
}

theme.Theme{
Data: myTheme,
ChildWidget: myApp,
}

Dynamic Theming

Switch themes at runtime:

type appState struct {
core.StateBase
isDark bool
}

func (s *appState) Build(ctx core.BuildContext) core.Widget {
var themeData theme.ThemeData
if s.isDark {
themeData = theme.DefaultDarkTheme()
} else {
themeData = theme.DefaultLightTheme()
}

return theme.Theme{
Data: themeData,
ChildWidget: widgets.Column{
ChildrenWidgets: []core.Widget{
widgets.Switch{
Value: s.isDark,
OnChanged: func(value bool) {
s.SetState(func() {
s.isDark = value
})
},
},
// Rest of your app
},
},
}
}

Nested Themes

Override theme for a subtree:

theme.Theme{
Data: theme.DefaultLightTheme(),
ChildWidget: widgets.Column{
ChildrenWidgets: []core.Widget{
lightContent,
// Dark section within light app
theme.Theme{
Data: theme.DefaultDarkTheme(),
ChildWidget: darkSection,
},
},
},
}

Next Steps