Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Theming

Every GUI window accepts a #theme parameter that controls the visual appearance of all widgets inside it. Graphix provides 22 built-in themes, plus two mechanisms for full customization: custom palettes and custom stylesheets.

Built-in Themes

The Theme type enumerates all available themes:

type Theme = [
  `Light,
  `Dark,
  `Dracula,
  `Nord,
  `SolarizedLight,
  `SolarizedDark,
  `GruvboxLight,
  `GruvboxDark,
  `CatppuccinLatte,
  `CatppuccinFrappe,
  `CatppuccinMacchiato,
  `CatppuccinMocha,
  `TokyoNight,
  `TokyoNightStorm,
  `TokyoNightLight,
  `KanagawaWave,
  `KanagawaDragon,
  `KanagawaLotus,
  `Moonfly,
  `Nightfly,
  `Oxocarbon,
  `Ferra,
  `Custom(StyleSheet),
  `CustomPalette(Palette)
];

Apply a theme by passing it to the window function:

window(#theme: &`CatppuccinMocha, &content)

Since #theme takes a &Theme, you can change the theme reactively:

let dark = true
let theme = select dark {
  true => `Dark,
  false => `Light
}

window(#theme: &theme, &content)

Custom Palettes

For quick color customization without defining per-widget styles, use `CustomPalette with a Palette:

type Palette = {
  background: Color,
  danger: Color,
  primary: Color,
  success: Color,
  text: Color,
  warning: Color
};

The palette defines the core colors from which iced derives all widget styles automatically:

  • background – window and container backgrounds.
  • text – default text color.
  • primary – accent color for buttons, sliders, active elements.
  • success – color for success states (e.g., toggler when enabled).
  • danger – color for destructive actions and error states.
  • warning – color for warning indicators.
use gui;
use gui::style;
use gui::text;
use gui::button;
use gui::toggler;
use gui::slider;
use gui::column;
mod icon;

let enabled = true;
let br = 0.0;
let cv = |base| min(1.0, base + br);

let my_palette = {
  background: color(#r: cv(0.1), #g: cv(0.1), #b: cv(0.15))$,
  text:       color(#r: cv(0.9), #g: cv(0.9), #b: cv(0.95))$,
  primary:    color(#r: cv(0.4), #g: cv(0.6), #b: cv(1.0))$,
  success:    color(#r: cv(0.3), #g: cv(0.8), #b: cv(0.4))$,
  danger:     color(#r: cv(1.0), #g: cv(0.3), #b: cv(0.3))$,
  warning:    color(#r: cv(1.0), #g: cv(0.8), #b: cv(0.2))$
};

let col = column(
  #spacing: &15.0,
  #padding: &`All(30.0),
  #width: &`Fill,
  &[
    text(#size: &24.0, &"Custom Palette"),
    button(#padding: &`All(10.0), &text(&"Primary Button")),
    toggler(#label: &"Enabled", #on_toggle: |v| enabled <- v, &enabled),
    slider(#min: &0.0, #max: &0.5, #step: &0.05, #on_change: |v| br <- v, &br),
    text(&"Brightness: [br]")
  ]
);

[&window(
  #icon: &icon::icon,
  #title: &"Custom Palette",
  #theme: &`CustomPalette(my_palette),
  &col
)]

Custom Palette

Custom Stylesheets

For full control over individual widget appearances, use `Custom(StyleSheet). A stylesheet combines a palette with optional per-widget style overrides:

type StyleSheet = {
  button: [ButtonStyle, null],
  checkbox: [CheckboxStyle, null],
  container: [ContainerStyle, null],
  menu: [MenuStyle, null],
  palette: Palette,
  pick_list: [PickListStyle, null],
  progress_bar: [ProgressBarStyle, null],
  radio: [RadioStyle, null],
  rule: [RuleStyle, null],
  scrollable: [ScrollableStyle, null],
  slider: [SliderStyle, null],
  text_editor: [TextEditorStyle, null],
  text_input: [TextInputStyle, null],
  toggler: [TogglerStyle, null]
};

Every widget style field is optional (union with null). When null, the widget inherits its style from the palette automatically.

The stylesheet Builder

Use the stylesheet function to construct a StyleSheet without filling in every field manually. Only #palette is required; all widget style parameters default to null:

val stylesheet: fn(
  #palette: Palette,
  ?#button: [ButtonStyle, null],
  ?#checkbox: [CheckboxStyle, null],
  ?#container: [ContainerStyle, null],
  ?#menu: [MenuStyle, null],
  ?#pick_list: [PickListStyle, null],
  ?#progress_bar: [ProgressBarStyle, null],
  ?#radio: [RadioStyle, null],
  ?#rule: [RuleStyle, null],
  ?#scrollable: [ScrollableStyle, null],
  ?#slider: [SliderStyle, null],
  ?#text_editor: [TextEditorStyle, null],
  ?#text_input: [TextInputStyle, null],
  ?#toggler: [TogglerStyle, null]
) -> StyleSheet;

Example with a custom palette and button override:

use gui;
use gui::style;
use gui::text;
use gui::button;
use gui::text_input;
use gui::slider;
use gui::toggler;
use gui::container;
use gui::column;
use gui::rule;
mod icon;

let palette = {
  background: color(#r: 0.12, #g: 0.12, #b: 0.18)$,
  text:       color(#r: 0.85, #g: 0.85, #b: 0.9)$,
  primary:    color(#r: 0.55, #g: 0.35, #b: 0.95)$,
  success:    color(#r: 0.2, #g: 0.8, #b: 0.5)$,
  danger:     color(#r: 0.95, #g: 0.25, #b: 0.35)$,
  warning:    color(#r: 1.0, #g: 0.7, #b: 0.1)$
};

let theme = `Custom(stylesheet(
  #palette: palette,
  #button: button_style(
    #background: color(#r: 0.55, #g: 0.35, #b: 0.95)$,
    #text_color: color(#r: 1.0, #g: 1.0, #b: 1.0)$,
    #border_radius: 12.0
  ),
  #text_input: text_input_style(
    #background: color(#r: 0.16, #g: 0.16, #b: 0.24)$,
    #border_color: color(#r: 0.55, #g: 0.35, #b: 0.95, #a: 0.5)$,
    #border_radius: 8.0,
    #border_width: 2.0,
    #value_color: color(#r: 0.9, #g: 0.9, #b: 0.95)$,
    #placeholder_color: color(#r: 0.5, #g: 0.5, #b: 0.6)$
  ),
  #slider: slider_style(
    #rail_color: color(#r: 0.3, #g: 0.3, #b: 0.4)$,
    #rail_fill_color: color(#r: 0.55, #g: 0.35, #b: 0.95)$,
    #handle_color: color(#r: 0.7, #g: 0.55, #b: 1.0)$,
    #handle_radius: 8.0
  ),
  #toggler: toggler_style(
    #background: color(#r: 0.3, #g: 0.3, #b: 0.4)$,
    #foreground: color(#r: 0.85, #g: 0.85, #b: 0.9)$
  ),
  #container: container_style(
    #background: color(#r: 0.15, #g: 0.15, #b: 0.22)$,
    #border_color: color(#r: 0.55, #g: 0.35, #b: 0.95, #a: 0.3)$,
    #border_width: 1.0,
    #border_radius: 10.0
  )
));

let name = "";
let volume = 50.0;
let dark_mode = true;

[&window(
  #icon: &icon::icon,
  #title: &"Custom Styles",
  #theme: &theme,
  &container(
    #padding: &`All(30.0),
    #width: &`Fill,
    #height: &`Fill,
    &column(
      #spacing: &15.0,
      #width: &`Fill,
      &[
        text(#size: &24.0, &"Custom Stylesheet Demo"),
        horizontal_rule(),
        text_input(
          #placeholder: &"Type something...",
          #on_input: |v| name <- v,
          &name
        ),
        slider(
          #min: &0.0, #max: &100.0,
          #on_change: |v| volume <- v,
          &volume
        ),
        text(&"Volume: [volume]"),
        toggler(
          #label: &"Dark mode",
          #on_toggle: |v| dark_mode <- v,
          &dark_mode
        ),
        button(#padding: &`All(12.0), &text(&"Styled Button"))
      ]
    )
  )
)]

Custom Styles

Per-Widget Style Types

Each widget style type is a struct where every field is optional ([T, null]). A null field means “inherit from the theme palette.” The GUI module provides both the types and corresponding builder functions.

ButtonStyle

type ButtonStyle = {
  background: [Color, null],
  border_color: [Color, null],
  border_radius: [f64, null],
  border_width: [f64, null],
  text_color: [Color, null]
};

val button_style: fn(
  ?#background: [Color, null],
  ?#border_color: [Color, null],
  ?#border_radius: [f64, null],
  ?#border_width: [f64, null],
  ?#text_color: [Color, null]
) -> ButtonStyle;

TextInputStyle

type TextInputStyle = {
  background: [Color, null],
  border_color: [Color, null],
  border_radius: [f64, null],
  border_width: [f64, null],
  icon_color: [Color, null],
  placeholder_color: [Color, null],
  selection_color: [Color, null],
  value_color: [Color, null]
};

val text_input_style: fn(
  ?#background: [Color, null],
  ?#border_color: [Color, null],
  ?#border_radius: [f64, null],
  ?#border_width: [f64, null],
  ?#icon_color: [Color, null],
  ?#placeholder_color: [Color, null],
  ?#selection_color: [Color, null],
  ?#value_color: [Color, null]
) -> TextInputStyle;

SliderStyle

type SliderStyle = {
  handle_border_color: [Color, null],
  handle_border_width: [f64, null],
  handle_color: [Color, null],
  handle_radius: [f64, null],
  rail_color: [Color, null],
  rail_fill_color: [Color, null],
  rail_width: [f64, null]
};

val slider_style: fn(
  ?#handle_border_color: [Color, null],
  ?#handle_border_width: [f64, null],
  ?#handle_color: [Color, null],
  ?#handle_radius: [f64, null],
  ?#rail_color: [Color, null],
  ?#rail_fill_color: [Color, null],
  ?#rail_width: [f64, null]
) -> SliderStyle;

Other Widget Styles

The remaining widget style types follow the same pattern – a struct of optional fields with a corresponding builder function:

TypeBuilderKey Fields
CheckboxStylecheckbox_styleaccent, background, border_color, border_radius, border_width, icon_color, text_color
ContainerStylecontainer_stylebackground, border_color, border_radius, border_width, text_color
MenuStylemenu_stylebackground, border_color, border_radius, border_width, selected_background, selected_text_color, text_color
PickListStylepick_list_stylebackground, border_color, border_radius, border_width, handle_color, placeholder_color, text_color
ProgressBarStyleprogress_bar_stylebackground, bar_color, border_radius
RadioStyleradio_stylebackground, border_color, border_width, dot_color, text_color
RuleStylerule_stylecolor, radius, width
ScrollableStylescrollable_stylebackground, border_color, border_radius, border_width, scroller_color
TextEditorStyletext_editor_stylebackground, border_color, border_radius, border_width, placeholder_color, selection_color, value_color
TogglerStyletoggler_stylebackground, background_border_color, border_radius, foreground, foreground_border_color, text_color

All builder functions accept the same labeled arguments as the corresponding struct fields, all optional, all defaulting to null.