Skip to main content

Theme

Struct Theme 

Source
pub struct Theme {
Show 51 fields pub appearance: Appearance, pub bg: Hsla, pub surface: Hsla, pub surface_raised: Hsla, pub surface_card: Hsla, pub surface_dialog: Hsla, pub surface_overlay: Hsla, pub element_hover: Hsla, pub element_active: Hsla, pub border: Hsla, pub border_strong: Hsla, pub text: Hsla, pub text_muted: Hsla, pub text_faint: Hsla, pub text_dim: Hsla, pub solid: Hsla, pub on_solid: Hsla, pub accent: Hsla, pub accent_strong: Hsla, pub on_accent: Hsla, pub danger: Hsla, pub danger_muted: Hsla, pub warning: Hsla, pub warning_muted: Hsla, pub success: Hsla, pub busy: Hsla, pub success_muted: Hsla, pub surface_raised_hover: Hsla, pub band: Hsla, pub input_bg: Hsla, pub selection: Hsla, pub cursor: Hsla, pub caret: Hsla, pub ring: Hsla, pub danger_strong: Hsla, pub code_text: Hsla, pub code_wash: Hsla, pub syntax: SyntaxPalette, pub diff_add: Hsla, pub diff_del: Hsla, pub diff_hunk_bg: Hsla, pub frost: FrostSpec, pub glass_regular: SurfaceSpec, pub glass_clear: SurfaceSpec, pub popover_surface: SurfaceStyle, pub glass_magnify: f32, pub glass_dispersion: f32, pub font_sans: SharedString, pub font_mono: SharedString, pub font_sans_fallback: SharedString, pub font_mono_fallback: SharedString,
}
Expand description

The app theme. Two concrete instances — Theme::dark and Theme::light.

Fields§

§appearance: Appearance

Which appearance these tokens were built for.

§bg: Hsla

Main content panel. Dark: the deepest plane (#060606). Light: pure white — long-form content reads best on an unbroken white field.

§surface: Hsla

Shell / sidebar surface. Dark: one step up from bg. Light: one step down (grey) — chrome recedes from the content plane in both, which is the direction a naive invert gets backwards.

§surface_raised: Hsla

Raised surface: opaque pills and chips that sit proud of the panel. Dark: lighter than surface. Light: white, separated by border + shadow rather than by lightness.

§surface_card: Hsla

Inline card resting on the main panel (auth gate, empty-state cards).

§surface_dialog: Hsla

Modal dialog, floating over a Theme::scrim.

§surface_overlay: Hsla

Popover, menu and command-palette surface — the highest plane.

§element_hover: Hsla

Hover wash for interactive rows/buttons.

§element_active: Hsla

Active/selected wash.

§border: Hsla

Hairline border.

§border_strong: Hsla

Stronger border for focused/raised edges.

§text: Hsla

Primary text. ~17.5:1 on its own background in both appearances.

§text_muted: Hsla

Muted text: timestamps, secondary labels. ~7.5–8:1.

§text_faint: Hsla

Faint text: placeholders, disabled. ~4.5:1 — AA for body copy.

§text_dim: Hsla

One notch below text_muted — the diff file-path tone. It exists as its own token rather than being folded into text_muted because the dark value was sampled (#989898) and folding it would shift that label, which is a palette change dressed up as a refactor.

§solid: Hsla

The maximum-contrast solid fill: near-white on dark, near-black on light. This is the primary button plate.

§on_solid: Hsla

Label/icon color on top of Self::solid — its inverse.

§accent: Hsla

Accent — the emphasis weight for text and icons.

Neutral by default, and deliberately. A component library that ships a hue puts that hue in every app that installs it, and bezel had an indigo running through spinners, pagination, date selection and list markers before anyone chose it. The default is now the same lightness with the chroma at zero.

This is the token to brand:

let mut theme = Theme::for_appearance(appearance);
theme.accent = my_brand_accent(appearance);

See set_palette, which is what makes an override survive an appearance switch.

§accent_strong: Hsla

Stronger accent for fills that carry Self::on_accent text. Neutral by default, it is the maximum-contrast plate — a mid grey would not carry a label the way the indigo it replaced did.

§on_accent: Hsla

Label color on top of Self::accent_strong.

§danger: Hsla

Danger — red (errors, stop button).

§danger_muted: Hsla

Softer danger for secondary/inline error copy.

§warning: Hsla

Warning — amber (offline notices, awaiting-input).

§warning_muted: Hsla

Softer warning for secondary copy.

§success: Hsla

Success / online — emerald.

§busy: Hsla

Working / streaming indicator — pink.

§success_muted: Hsla

Softer success for text on a success-tinted chip.

§surface_raised_hover: Hsla

Hover tone for an opaque raised pill. Hover must brighten the plate in dark mode, never swap it for a translucent wash (that made pills go see-through — user-reported); in light mode it darkens instead, same idea.

§band: Hsla

Recessed band behind a palette/picker header or footer strip. Translucent so the glass still reads through.

§input_bg: Hsla

The composer pill and other input plates.

Its own token because “lifted” inverts between appearances. On dark, a faint white wash over near-black reads as raised. The literal light translation — a faint black wash on white — reads as recessed, a dent rather than a plate, which is why the prompt looked like bare text on a smudge. Light mode lifts the way light UIs actually do: pure white, with the border and shadow carrying the elevation.

§selection: Hsla

Text-selection highlight in the composer and inputs.

§cursor: Hsla

Terminal block cursor.

§caret: Hsla

Text caret.

The body text colour, because that is what a caret is: the next glyph, before you type it. It was a sampled blue once — carried over from the app this library was extracted from, derived from nothing here — which is why a caret in a plain paragraph arrived tinted.

§ring: Hsla

Keyboard focus ring — a hairline, so it marks the control without restating the label inside it.

§danger_strong: Hsla

Destructive-action button fill (danger plate, carries Self::on_accent).

§code_text: Hsla

Inline-code text. Neutral: code is already set apart by the mono face and its wash, and a hue on top reads as a link rather than as code.

§code_wash: Hsla

Inline-code wash behind Self::code_text.

§syntax: SyntaxPalette

Shared paint-only syntax palette.

§diff_add: Hsla

Diff: added lines.

§diff_del: Hsla

Diff: deleted lines.

§diff_hunk_bg: Hsla

Diff: hunk-header wash (bluish grey).

§frost: FrostSpec

The surfaces this theme can paint. Blur belongs to the look, not to the caller: Apple exposes no blur parameter on either family, only the thickness or the variant.

§glass_regular: SurfaceSpec§glass_clear: SurfaceSpec§popover_surface: SurfaceStyle

What the popover surfaces — menus, dialogs, sheets, tooltips — mount on. They take no theme of their own, so this is where the choice lives; a component that owns its surface names its own style instead.

§glass_magnify: f32

Lens displacement amplitude, signed; negative inverts it.

§glass_dispersion: f32

Per-channel spread of that displacement — the chromatic fringe.

§font_sans: SharedString

UI font family — the name the text system resolves, not the bytes. Point it at your own family once you have registered that font with the text system; a family nothing registered falls through to the fallback below.

§font_mono: SharedString

Monospace family for code/terminal.

§font_sans_fallback: SharedString

Explicit system fallbacks, for callers that want to skip the lookup.

§font_mono_fallback: SharedString

Implementations§

Source§

impl Theme

Source

pub fn branded(brand: &Brand, appearance: Appearance) -> Self

The shipped palette for an appearance, rotated onto a brand. What Theme::install builds, without installing it — for previewing the appearance you are not currently painting.

Source§

impl Theme

Source

pub fn glass(&self) -> Hsla

The frost tint painted over the blurred window background (macOS glass), at Brand::glass’s alpha. Dark: darker than surface, matched to the reference vibrancy scrim hsl(0 0% 3%). Light: a near-white frost. Opaque, this IS the surface tone.

Source

pub fn window_bg(&self) -> Hsla

The app’s root fill: the frost where glass is on, the opaque panel where it is not. What a root element paints instead of Self::bg, so a window that opens blurred is not then covered over by the paint that made the blur pointless.

Source

pub fn is_glass(&self) -> bool

Whether this appearance paints translucent chrome over the blurred desktop. Glass-only recipes — backdrop blurs, translucent popover tints, per-glyph edge fades — must gate on this rather than reading the brand’s alpha, because an opaque appearance can still be asked for one.

Source

pub fn glass_hover(&self) -> Hsla

Hover wash for chrome that sits ON GLASS (sidebar rows, tabs, titlebar buttons). One recipe, both appearances: the 11% wash, tone-flipped by the palette convention (soft-white on dark, soft-black on light).

Hover and selection share the SAME fill (selection adds only the ring). Light previously ran heavy white washes here (hover 0.55, selection 0.92) after a black-hover-next-to-white-selection mismatch report; now hover and selection are both the tone-flipped wash, so they lift the same way again. Light’s alpha sits under dark’s: dark’s 11% at the light tone read too dark over the bright frost (user report).

Source

pub fn glass_overlay(&self) -> Hsla

The translucent tint floating cards paint over their backdrop blur (see bezel::material). Dark: the reference .glass-surface menu tint verbatim — oklch(0.33 0 0 / 34%). The previous surface_overlay at 65% was tuned back when the tint had to approximate the composited recipe without a real blur; kept over the blur it buried the backdrop’s colour and menus read as flat grey slabs next to the hue-inheriting chrome (user report). At 34% the blurred backdrop carries the card and the mid-grey only lifts it off the plane. Light: heavier — a translucent white tint left menu text ghosting over whatever sat behind the popover, so light coverage steps up to keep rows on a known background.

Source

pub fn input_glass_bg(&self) -> Hsla

The composer pill / question panel fill. Light’s input_bg is opaque white (the elevation ladder on an opaque page) — over glass it read as a solid slab in front of the frosted blur, so it thins to a translucent tint there (0.6 and then 0.45 both still read too bright over the 0.80 frost — lowered on user request). Dark’s 3% white wash is already glass-native.

Source

pub fn card_glass_bg(&self) -> Hsla

Section-card fill (settings cards and similar in-panel cards). The opaque surface tone read as a harsh solid slab floating on the frosted blur (user report), so glass thins it to a translucent tint; opaque platforms keep the true card tone.

Source

pub fn scrim(&self) -> Hsla

The standard modal backdrop — see scrim.

Source

pub fn window_background_appearance(&self) -> WindowBackgroundAppearance

How the platform should composite the window behind our paint. The mode falls out of the alpha: frost under 1.0 wants the blurred desktop, opaque wants opaque compositing (subpixel-friendly, no vibrancy cost for a blur nothing shows).

This is a method rather than a constant because it has to be re-applied after every theme swap: gpui’s macOS backend tears the NSVisualEffectView out of the hierarchy whenever the value is anything but Blurred, and the re-apply in appearance::apply is what restores vibrancy when the user switches back to dark. See zed’s crates/zed/src/main.rs, which runs the same loop on every settings change.

Source§

impl Theme

Source

pub fn install(appearance: Appearance, cx: &mut App)

Install the palette for appearance as the gpui global and point the context-free paint helpers at it. The only way the appearance should change — setting the global directly leaves current_appearance stale.

Which palette that is comes from set_palette, so an app with its own colours keeps them across a light/dark switch.

Source

pub fn install_custom(theme: Theme, cx: &mut App)

Install a palette the caller built: brand colours, one retuned token, or a wholesale replacement. Theme is a plain struct with public fields, so the usual shape is Theme::light() with a few fields overwritten.

Use this rather than cx.set_global(theme). The context-free paint helpers (ink, hairline, wash, …) read current_appearance and not the global, so a palette installed around this one leaves them painting for whatever appearance was last installed — light washes over a dark palette, and nothing to point at.

One-shot: appearance::apply rebuilds the palette whenever the appearance changes, so what is installed here is replaced on a light/dark switch. For colours that survive that, register a builder with set_palette instead.

Source

pub fn of(cx: &App) -> &Theme

Read the theme global.

Source§

impl Theme

Source

pub const GLASS_ALPHA: f32

The frost alpha Brand::glass starts from. Matched by eye to a reference Electron app’s dark glass: its scrim is 0.76 over hsl(0 0% 3%), but sits on the under-window vibrancy MATERIAL, which pre-darkens the blur; a bare backdrop blur has no such layer, so ours runs heavier to land on the same perceived tone.

Opaque off macOS: Linux and Windows get no compositor-blur guarantee, and a merely transparent window would show raw desktop through the sidebar. An app that knows its compositor sets the brand field anyway.

Source

pub const HEADER_HEIGHT: f32 = 44.0

Main-panel header height (the reference h-11) — in-card headers (changes pane).

Source

pub const TITLEBAR_HEIGHT: f32 = 38.0

The unified window titlebar (traffic lights + cluster + tabs). Content rides Self::TITLEBAR_TOP_PAD lower than center so the air above matches the perceived gap to the inset card below (border + card body).

Source

pub const TITLEBAR_TOP_PAD: f32 = 2.0

Downward shift of titlebar content within the bar.

Source

pub const TRAFFIC_LIGHT_INSET: f32

Leading room the macOS traffic lights need where AppKit puts them — zed’s TRAFFIC_LIGHT_PADDING on the macOS 26 SDK (71.0 before it), and the same 78 ../desktop measured for its Tauri window. An app that moves the lights with TitlebarOptions::traffic_light_position owns this number too.

Source

pub const STATUS_STRIP_HEIGHT: f32 = 24.0

Reserved status strip under the content outlet (the reference h-6) — the WorkingIndicator row; reserving it keeps the composer from shifting.

Source

pub const TRANSCRIPT_FADE_BAND: f32 = 24.0

Height of the gradient that fades the transcript into the panel background at its bottom edge. The transcript’s last row must pad itself past this band so settled content (message text, the hover-revealed timestamp) never sits inside the fade when scrolled to the bottom.

Source

pub const BASE_RADIUS: f32 = 8.0

Button, text field and select-trigger radius — the crate’s most-used corner after the derived ones, and unnamed until the concentric pass separated the eight sites that chose 8.0 from the ones that only arrived at it as 12 − 4.

Every other corner is a ratio of this one, so Brand::radius moves the whole set together.

Source

pub const SPACE_XS: f32 = 4.0

Base spacing steps.

Source

pub const SPACE_SM: f32 = 8.0

Source

pub const SPACE_MD: f32 = 12.0

Source

pub const SPACE_LG: f32 = 16.0

Source

pub fn bubble_radius() -> f32

Message bubble corner radius.

Source

pub fn surface_radius() -> f32

Floating-surface corner radius — popovers, menus, the command palette, group boxes.

A glass surface paints this on its border and hands the same number to bezel::ui::surface’s backdrop blur. The two must agree: a blur cut to a different radius frosts square corners outside a round border, and it shows only on glass and only at the corners. So the radius is named once and read at both ends, rather than written twice sixty lines apart — which is how three independent 12.0s came to exist here.

Source

pub fn panel_radius() -> f32

Panel / card corner radius.

Source

pub fn button_radius() -> f32

Button, text field and select-trigger radius.

Source

pub fn control_radius() -> f32

Small control radius (chips, tags, steppers) — a size down from Self::button_radius, for things that sit inside a control rather than being one.

Source

pub const fn inset_radius(outer: f32, inset: f32) -> f32

The concentric child of a surface: a row inset by inset inside a container of radius outer keeps its corners parallel to the container’s, rather than looking pasted onto it.

This is SwiftUI’s ContainerRelativeShape rule done as arithmetic. gpui has no container shape to inherit at paint time, so the relationship is stated where the child is defined instead of resolved at runtime — which means a container that changes its padding carries its rows with it, and the derived value never becomes a constant of its own.

Source§

impl Theme

Source

pub fn dark() -> Self

Build the dark theme. The surface tones are sampled straight from the reference screenshots of the original app (docs/reference): main panel #060606, shell/sidebar #0d0d0d.

Source

pub fn light() -> Self

Build the light theme.

Neutrals are the same oklch scale read from the other end, but the roles are reassigned rather than mirrored (see the module docs): content plane white, chrome grey, raised surfaces white-plus-shadow. Text tones are picked to reproduce the dark theme’s contrast ratios, and accents drop from the 400 to the 600 step at identical hue so they clear WCAG AA on white instead of glowing.

Source

pub fn for_appearance(appearance: Appearance) -> Self

Build the theme for an appearance.

Source§

impl Theme

Source

pub fn ink(&self, alpha: f32) -> Hsla

Overlay ink at alpha — see ink.

Source

pub fn hairline(&self, alpha: f32) -> Hsla

Hairline ink at alpha — see hairline.

Source

pub fn wash(&self, alpha: f32) -> Hsla

State wash at alpha — see wash.

Trait Implementations§

Source§

impl Clone for Theme

Source§

fn clone(&self) -> Theme

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Theme

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Theme

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl Global for Theme

Source§

impl ThemeExt for Theme

Source§

fn theme(&self) -> &Theme

Auto Trait Implementations§

§

impl Freeze for Theme

§

impl RefUnwindSafe for Theme

§

impl Send for Theme

§

impl Sync for Theme

§

impl Unpin for Theme

§

impl UnsafeUnpin for Theme

§

impl UnwindSafe for Theme

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> ReadGlobal for T
where T: Global,

Source§

fn global(cx: &App) -> &T

Returns the global instance of the implementing type. Read more
Source§

impl<R, P> ReadPrimitive<R> for P
where R: Read + ReadEndian<P>, P: Default,

Source§

fn read_from_little_endian(read: &mut R) -> Result<Self, Error>

Read this value from the supplied reader. Same as ReadEndian::read_from_little_endian().
Source§

fn read_from_big_endian(read: &mut R) -> Result<Self, Error>

Read this value from the supplied reader. Same as ReadEndian::read_from_big_endian().
Source§

fn read_from_native_endian(read: &mut R) -> Result<Self, Error>

Read this value from the supplied reader. Same as ReadEndian::read_from_native_endian().
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> UpdateGlobal for T
where T: Global,

Source§

fn update_global<C, F, R>(cx: &mut C, update: F) -> R
where C: BorrowAppContext, F: FnOnce(&mut T, &mut C) -> R,

Updates the global instance of the implementing type using the provided closure. Read more
Source§

fn set_global<C>(cx: &mut C, global: T)

Set the global instance of the implementing type.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more