Styling#
Styling in ttkbootstrap runs through one engine and reaches widgets three ways.
The Style engine owns the active theme and builds ttk styles on demand. The
shipped widgets carry the bootstyle keyword; to put that keyword on a widget
ttkbootstrap does not ship, use the delivery helpers below. And when a name in
the bootstyle vocabulary can’t describe the look you want, the toolkit builds
a ttk style by hand. The Custom styles guide shows the toolkit in use.
The style engine#
Style is a process-wide singleton, bound to the first application window and
reachable as its style attribute (or Style.get_instance()). It holds the
theme definitions, switches the active theme, and exposes the current theme’s
colors.
- class Style(*args, **kwargs)#
Bases:
StyleA singleton class for creating and managing the application theme and widget styles.
This class is meant to be a drop-in replacement for
ttk.Styleand inherits all of it’s methods and properties. However, in ttkbootstrap, this class is implemented as a singleton. Subclassing is not recommended and may have unintended consequences.- Parameters:
theme (str) – The name of the theme to use when styling the widget.
themenameis a permanent, non-deprecated alias accepted for the same purpose (pre-2.0 spelling); pass either.light_theme (str) – Optionally designate the themes that
toggle_theme()/theme_modeswitch between. If omitted, the counterpart is derived from the<family>-light/<family>-darknaming convention, so designation is only needed to pin a specific pair (e.g. a light theme from one family with a dark theme from another). Read once on the firstStyle/App; ignored on the existing singleton (set later viaset_theme_modes(...)).dark_theme (str) – Optionally designate the themes that
toggle_theme()/theme_modeswitch between. If omitted, the counterpart is derived from the<family>-light/<family>-darknaming convention, so designation is only needed to pin a specific pair (e.g. a light theme from one family with a dark theme from another). Read once on the firstStyle/App; ignored on the existing singleton (set later viaset_theme_modes(...)).default_button (str) – The color a bare
Button/Menubutton(nobootstyle) uses. Defaults to"neutral"; pass"primary"for the pre-2.0 accented default. Read once when the base styles build, so set it on the firstStyle/App; ignored on the existing singleton. If omitted, a pre-rootttk.set_default_button(...)setting is used, else"neutral"; an explicit argument here wins over that setter.
- static get_instance()#
Returns the singleton
Styleinstance (orNoneif not yet created).
- clear_image_cache()#
Drop all cached widget asset images.
Releases the cached
PhotoImageobjects (and their underlying Tcl images). This is a memory-reclamation and diagnostics escape hatch, not a live refresh: styles are built once per(theme, style), so styles built before the clear keep referencing the freed image names until they are rebuilt – which happens when a not-yet-built theme is activated, not on a same-theme switch. Clear when image widgets for the affected styles are not currently displayed (e.g. before moving to a fresh theme), or to reclaim memory at shutdown.
- configure(style, query_opt=None, **kw)#
Configure a ttk style, resolving
stylethrough the bootstyle parser if it is not already a registered ttk style name.- Parameters:
style (str) – A ttk style name or a
bootstylestring to resolve first.query_opt (Any) – If given, query this single style option instead of setting options; forwarded to
ttk.Style.configure.**kw – Style options to configure (forwarded to
ttk.Style.configure).
- element_create(elementname, etype, *args, **kw)#
Create a ttk element, idempotently within the current theme.
ttk raises
Duplicate elementif the same element name is created twice in one theme. Every ttkbootstrap theme maps to a single clam-derived Tcl theme with fixed colors, so an element only ever needs to be created once per theme; the second run of a recipe – whether a test that force-rebuilds a style, or a production theme-rebuild after the per-theme style registry (_theme_styles) desyncs from the Tcl theme – must be a safe no-op, not a crash. Theconfigure/layout/mapsteps that follow are already idempotent, so skipping the redundant element create makes the whole recipe re-runnable.
- load_user_theme(theme)#
Load a user theme definition
- Parameters:
theme (ThemeDefinition)
- load_user_themes(file)#
Load user themes saved in json format
- on_theme_change(callback, *, call_now=True)#
Register
callback(style)to run after every theme change.Use it to (re)build a custom style so it tracks the active theme: the callback re-runs on each
theme_use/toggle_theme. Whencall_now(the default), it also runs once immediately if a theme is already active, so the style exists before the first switch.Returns
callback, so it doubles as a decorator.
- register_theme(definition)#
Register a theme definition for use by the
Styleobject. This makes the definition and name available at run-time so that the assets and styles can be created when needed.- Parameters:
definition (ThemeDefinition) – A
ThemeDefinitionobject.
- remove_theme_change_callback(callback)#
Unregister a callback previously passed to
on_theme_change.- Return type:
None
- reset_style_options(style=None)#
Drop durable style-option overrides recorded via
configure().With no argument, clears every recorded override; with a style name, clears only that one. The recipe’s default value returns the next time the affected style is rebuilt (a theme switch or a new variant build).
- Parameters:
style (str, optional) – The style name to reset;
None(default) resets all.
- set_theme_modes(light=None, dark=None)#
Designate the light and/or dark theme that
theme_mode/toggle_theme()switch between.By default the counterpart is derived from the
<family>-light/<family>-darknaming convention, so this is only needed to pin a specific pair (e.g. a light theme from one family with a dark theme from another). Each name must be a registered theme; a name whose own type disagrees with the slot it is assigned to earns a warning.
- style_exists_in_theme(ttkstyle)#
Check if a style exists in the current theme.
- Parameters:
ttkstyle (str) – The ttk style to check.
- Returns:
bool –
Trueif the style exists, otherwiseFalse.
- theme_create(themename, parent=None, settings=None)#
Create a new theme in the Tcl interpreter. If the parent is a registered ttkbootstrap theme, the new theme will be registered with a copied ThemeDefinition and builder. Duplicate registration is avoided.
- theme_names()#
Return a list of all ttkbootstrap themes.
- Returns:
list[str, …] – A list of theme names.
- theme_use(themename=None)#
Changes the theme used in rendering the application widgets.
If themename is None, returns the theme in use, otherwise, set the current theme to themename, refreshes all widgets and emits a
<<ThemeChanged>>event.Only use this method if you are changing the theme during runtime. Otherwise, pass the theme name into the Style constructor to instantiate the style with a theme.
- Parameters:
themename (str) – The name of the theme to apply when creating new widgets
- Returns:
Union[str, None] – The name of the current theme if
themenameis None otherwise,None.
- toggle_theme()#
Toggle between the light and dark theme, returning the new mode.
- Return type:
str | None
- use_dynamic_foreground(enable=True)#
Enable or disable dynamic foreground color selection.
When enabled, the foreground color of widgets will be decided between the
fgandselectfgcolors based on the contrast ratio with the widget’s background color. At default, this is disabled.- Parameters:
enable (bool) – If
True, dynamic foreground selection is enabled. Otherwise, it is disabled.
- property colors#
An object that contains the colors used for the current theme.
- Returns:
Colors – The colors object for the current theme.
- property dynamic_foreground#
Returns
Trueif dynamic foreground selection is enabled, otherwiseFalse.
- instance = None#
- property theme_mode: str | None#
The active theme mode (
"light"or"dark").Read it, or assign
"light"/"dark"to switch the current family to that mode (the designated theme, else the-light/-darksibling):style.theme_mode # -> "light" style.theme_mode = "dark" # switch
Reads the active theme’s mode;
Nonebefore a theme is applied.
Applying styles to any widget#
The widgets ttkbootstrap ships already accept bootstyle. These helpers extend
that keyword to widgets it does not ship — a third-party ttk widget, or a plain
tkinter.ttk widget you created yourself.
How much of the bootstyle vocabulary applies depends on the widget’s ttk
class. A widget that keeps a standard ttk class (a subclass of ttk.Button,
ttk.Entry, …) gets the full vocabulary and behaves exactly like the
corresponding ttkbootstrap widget. A widget with its own ttk class has no
ttkbootstrap style recipe: a bare color (bootstyle="info") warns and leaves
the widget’s style unchanged, and naming a base type explicitly
(bootstyle="info-frame") borrows that standard recipe where the widget’s
elements support it.
A composite widget’s internals follow the active theme on their own —
standard-class children resolve against the per-theme base styles, so they
match every theme switch without any wrapping. The accent, however, is not
fanned out to them: which child should carry it is the widget’s design, not
something a wrapper can infer. To accent a specific internal, call
apply_bootstyle on that child.
- bootify(cls)#
Return a
bootstyle-enabled subclass of any ttk widget class.Use this to wrap a third-party ttk-derived widget that ttkbootstrap does not ship a subclass for:
ThemedGadget = bootify(Gadget) gadget = ThemedGadget(root, bootstyle="info")
The result is
type(cls.__name__, (BootMixin, cls), {})— the same construction used for the widgets ttkbootstrap ships, so it gains the fullbootstyleAPI without mutating the original class.How much of the vocabulary applies depends on the widget’s ttk class:
A widget that keeps a standard ttk class (a subclass of
ttk.Button,ttk.Entry, …) gets the full vocabulary — it behaves exactly like the corresponding ttkbootstrap widget.A widget with its own ttk class has no ttkbootstrap style recipe: a bare color (
bootstyle="info") warns and leaves the widget’s style unchanged. Name a base type explicitly (bootstyle="info-frame") to borrow a standard recipe where the widget’s elements support it.
A composite widget’s internals follow the active theme on their own (standard-class children resolve against the per-theme base styles), but the accent is not fanned out to them — which child should carry it is the widget’s design, not something a wrapper can infer. To accent a specific internal, use
apply_bootstyleon that child.
- apply_bootstyle(widget, bootstyle)#
Apply a bootstyle to an existing widget instance, no class mutation.
For per-instance styling of a widget whose class was never wrapped (for example a plain
tkinter.ttkwidget): resolves the bootstyle to a ttk style, assigns it, and stamps the widget current for the theme walk.from tkinter import ttk b = ttk.Button(root, text="Save") apply_bootstyle(b, "success")
The same widget-class rules as
bootifyapply: a widget with its own ttk class has no style recipe, so a bare color warns and leaves the style unchanged — name a base type explicitly ("info-frame") to borrow a standard recipe.Returns the resolved ttk style name.
- Parameters:
bootstyle (Literal['danger', 'danger ghost', 'danger ghost toolbutton', 'danger link', 'danger outline', 'danger outline toolbutton', 'danger round', 'danger round toggle', 'danger square toggle', 'danger striped', 'danger thin', 'danger toggle', 'danger toolbutton', 'dark', 'dark ghost', 'dark ghost toolbutton', 'dark link', 'dark outline', 'dark outline toolbutton', 'dark round', 'dark round toggle', 'dark square toggle', 'dark striped', 'dark thin', 'dark toggle', 'dark toolbutton', 'ghost', 'ghost toolbutton', 'info', 'info ghost', 'info ghost toolbutton', 'info link', 'info outline', 'info outline toolbutton', 'info round', 'info round toggle', 'info square toggle', 'info striped', 'info thin', 'info toggle', 'info toolbutton', 'light', 'light ghost', 'light ghost toolbutton', 'light link', 'light outline', 'light outline toolbutton', 'light round', 'light round toggle', 'light square toggle', 'light striped', 'light thin', 'light toggle', 'light toolbutton', 'link', 'neutral', 'neutral ghost', 'neutral ghost toolbutton', 'neutral link', 'neutral outline', 'neutral outline toolbutton', 'neutral toolbutton', 'outline', 'outline toolbutton', 'primary', 'primary ghost', 'primary ghost toolbutton', 'primary link', 'primary outline', 'primary outline toolbutton', 'primary round', 'primary round toggle', 'primary square toggle', 'primary striped', 'primary thin', 'primary toggle', 'primary toolbutton', 'round', 'round toggle', 'secondary', 'secondary ghost', 'secondary ghost toolbutton', 'secondary link', 'secondary outline', 'secondary outline toolbutton', 'secondary round', 'secondary round toggle', 'secondary square toggle', 'secondary striped', 'secondary thin', 'secondary toggle', 'secondary toolbutton', 'square toggle', 'striped', 'success', 'success ghost', 'success ghost toolbutton', 'success link', 'success outline', 'success outline toolbutton', 'success round', 'success round toggle', 'success square toggle', 'success striped', 'success thin', 'success toggle', 'success toolbutton', 'thin', 'toggle', 'toolbutton', 'warning', 'warning ghost', 'warning ghost toolbutton', 'warning link', 'warning outline', 'warning outline toolbutton', 'warning round', 'warning round toggle', 'warning square toggle', 'warning striped', 'warning thin', 'warning toggle', 'warning toolbutton'] | str)
- Return type:
- enable_global_api()#
Re-apply the legacy global monkey-patch (opt-in).
By default the styling API is delivered through concrete subclasses (
BootMixin/AutoStyleMixin), so importing ttkbootstrap does not mutate the stocktkinter/tkinter.ttkclasses. Call this once if you have code that creates vanilla ttk/tk widgets (e.g.from tkinter import ttk; ttk.Button(..., bootstyle=...)) and want thebootstyle/autostylekeywords on them anyway. It also makespack/grid/placereturn the widget on every widget (seeBootstyle.patch_geometry_managers), extendingFluentGeometryMixinbeyond the blessed subclasses.Idempotent. The installed wrappers defer to
BootMixin/AutoStyleMixininstances (the blessed subclasses), so enabling the global API never double-resolves a style for a widget that already carries a mixin.
Building custom styles#
For a look bootstyle can’t name, compose a ttk style from assets,
elements, a state map, and a layout — each a small toolkit call.
Assets renders cached images, image_element turns one into a named ttk
element, state_map is a validated style.map, and layout arranges the
elements into the widget’s element tree and registers the style. See the
Custom styles guide for a
worked example.
- class Assets(style)#
Bases:
objectImage construction over the engine’s content-addressed cache.
Assets(style)wrapsStyle._get_or_create_image: each method renders an asset and derives its cache key from the same render inputs, so the key cannot drift from the pixels. Builders reach a shared instance viaself.assets; public users constructAssets(Style.get_instance()).Sizes are logical UI units converted once by the root-bound scaling service; final image dimensions are exact and may be odd. Every method returns the Tcl image name (the
_get_or_create_imagecontract), and the resolved colors are in the key, so cross-theme-identical assets dedupe.- circle(fill, size, *, outline=None, width=0)#
A filled circle;
sizeandwidthare logical UI units.
- icon(name, size, color)#
Render a Bootstrap Icons glyph as a cached widget asset.
sizeis the logical UI size;coloris a resolved color string. Returns the Tcl image name (the same contract as the shape recipes). The key is("icon", name, physical_size, color)– theme -independent by construction (the resolved color is in the key), so two themes that resolve a glyph to the same color share one image.IconRendereris imported lazily here soassets.pykeeps no module -level edge toicons.py(which imports this module), and the font is never read at import time.
- image(size, draw_fn, *key_parts)#
Escape hatch for custom composite draws (concentric circles, glyphs).
draw_fn(draw, w, h)draws onto the oversampled(w, h)canvas, so the old hand-fit canvas constants becomew-relative expressions. The key is(draw_fn.__qualname__, physical_size, *key_parts)– list inkey_partsevery color/value the draw closes over; they sit beside the draw so the key cannot silently drift from it, and the__qualname__keeps two different draws from colliding on equalkey_parts.
- recolor(name, *, white, black, magenta=None, transform=None)#
Recolor a manifest-backed ttk element raster and cache the result.
white,black, and optionalmagentaare resolved color strings for the source template’s semantic channels. Source alpha is preserved.transformmay flip the image horizontally ("flip-x") or rotate it by 90/180/270 degrees ("rotate-90"/"rotate-180"/"rotate-270"); dimensions and border/padding metadata transform with the pixels.Returns a
RecolorResultcontaining the Tcl image name and scaled logical manifest metadata. Source-image dimensions only validate the vendored PNG; callers do not pass a size.
- rect(fill, size)#
A solid axis-aligned rectangle (no anti-aliasing, no size snap).
- rounded_rect(fill, size, radius, *, outline=None, width=0)#
A rounded rectangle with geometry in logical UI units.
- image_element(style, name, *, default, states=None, **options)#
Create an image element with a validated, ordered state->image map.
Wraps
style.element_create(name, "image", default, *statespecs, **options).statesis an ordered dict{state_string: image}; ttk matches statespecs first-match-wins, so the dict’s insertion order is the match order, made explicit. Each state string is validated bystatespec(a typo raises instead of silently never matching).options(width, border, sticky, …) pass through toelement_create.
- state_map(style, ttk_style, **options)#
Validated
style.mapanalog.Each keyword is a ttk option (e.g.
foreground=) whose value is an ordered dict{state_string: value}(or an iterable of(state_string, value)pairs). State strings are validated bystatespec. Replaces bareforeground=[("disabled", fg)]lists.
- statespec(spec)#
Validate a ttk state string and split it into a tuple of tokens.
Tokens are space-separated; each may be negated with a leading
!(“!selected”). An unknown token raisesValueError.
- layout(style, ttk_style, root)#
Apply an
El(or list ofEl`s) as the layout for `ttk_style.Structural sugar over
style.layout(ttk_style, [...]). Defining a layout is what gives a style its identity, so this also registersttk_stylewith the engine (viaregister_style) – a hand-built style whose terminal step islayout()resolves throughstyle="<ttk_style>"with no extra step. (Built-in builders that also call_register_ttkstyleexplicitly are unaffected – registration is an idempotent set add.)
- class El(name, *, side=None, sticky=None, expand=None, border=None, children=None)#
Bases:
objectA ttk layout element: a name, layout options, and child elements.
Build an
Eltree and pass it tolayout(), which lowers it to ttk’s nested(name, {options, "children": [...]})form and registers the style.- Parameters:
name (str) – The element name (e.g.
"Button.border").side (str) – Which side of the remaining space the element occupies:
"left","right","top", or"bottom".sticky (str) – How the element stretches within its allocation — any combination of
"nsew".expand (bool) – Whether the element claims any leftover space.
border (int) – The border width reserved inside the element.
- spec()#
Lower this element (and its subtree) to a ttk
(name, opts)tuple.
- register_style(style, ttk_style)#
Register a hand-built ttk style name with the ttkbootstrap engine.
A custom style applied to a ttkbootstrap widget via
style="My.TButton"is silently re-resolved to its base style unless the engine knows the name –bootstyleresolution only honorsstyle=for a registered style. Building a style with the toolkit (element_create/image_element/icon_element/map) does not register it on its own; call this (orlayout(), which calls it for you) sostyle="<ttk_style>"resolves to what you built.Registration is per active theme (it mirrors the built-in builders). A hand-built style is not auto-rebuilt on a theme switch, so re-build + re -register it if you change themes – engine-managed theme-follow for custom styles is a separate effort.
- class StyleName(ttk_class, colorname='default', orient=None, surface='')#
Bases:
objectDerive the related names a custom style is built from.
From a ttk class token (
"TScale","TRadiobutton"), a color name, and an optional orientation, computes the style name and the matching element-name prefix, so the three always agree.- Parameters:
ttk_class (str) – The ttk widget class token (e.g.
"TButton","Treeview").colorname (str) – The accent color name;
DEFAULTor""resolves to"primary".orient (str) – An optional orientation segment (
"Horizontal"/"Vertical").surface (str) – An optional surface-color token carried as a name prefix.
- colorname#
The resolved color name —
"primary"when the input was the default, otherwise the input unchanged.- Type:
- ttk_style#
The full ttk style name (
"Horizontal.TScale","info.Horizontal.TScale","TRadiobutton", …).- Type:
- element#
The element-name prefix:
ttk_stylewith the class token’s leading"T"dropped ("info.Horizontal.TScale"→"info.Horizontal.Scale").- Type:
- property ttkstyle#
Backward-compatible spelling of
ttk_style.
Note
To render a glyph as an element in a custom layout, see
icon_element() on the Imaging page.
See also#
Custom styles — how to build and apply your own styles, with examples.
Theming & Colors — the theme model behind the engine.