Skip to main content

Styling

Every component takes the same flat style object RN components take (ViewStyle/TextStyle/ImageStyle, all aliases of one style bag on this platform). The pipeline splits that object in two: StyleSheet.flatten → splitStyle divides it into a layout half and a visual half. Layout keys go to the Yoga engine (LayoutNodeApi.setStyle) and never reach CSS; visual keys are turned into GTK CSS (visualStyleToCss) and applied through a memoized class registry, one class per unique declaration. overflow is the one key that crosses both halves — see below.

Layout fidelity is exact: every container runs its own layout manager that obeys only what Yoga computes, so a GTK widget's own minimum size never leaks into the layout, a window shrinks as freely as Yoga allows, and Dimensions.get("window") reports the same thing RN's app window reports — the window's content area under its header bar.

A property's status is one of:

  • supported — works fully;
  • partial — works, with the caveat in its note;
  • ignored — outside the frozen style contract; a value is accepted, a warning fires once per key, and the value is dropped.

Layout (routed to Yoga)​

The gallery's Layout section: flexDirection, justifyContent and alignItems arranging boxes under Yoga.

alignContent, alignItems, alignSelf, aspectRatio, bottom, columnGap, direction, display, flex, flexBasis, flexDirection, flexGrow, flexShrink, flexWrap, gap, height, justifyContent, left, margin, marginBottom, marginHorizontal, marginLeft, marginRight, marginTop, marginVertical, maxHeight, maxWidth, minHeight, minWidth, overflow, padding, paddingBottom, paddingHorizontal, paddingLeft, paddingRight, paddingTop, paddingVertical, position, right, rowGap, top, width — all supported, with behavior defined by the layout engine itself.

The gallery's Clipping section: overflow: "hidden" cutting a View to its rounded shape, with hit-testing stopping at the same clip.

overflow is the one key that does not stop at Yoga: Yoga needs it while measuring (a scroll node's main axis is unconstrained), and the widget needs it to clip. GTK4 CSS has no overflow property, so this is a direct widget call rather than a CSS declaration — the only style outside transform whose GTK half is not CSS. hidden clips paint and hit-testing to the widget's CSS padding box, rounded by borderRadius; scroll clips the same way and adds no scrolling of its own — matching RN, where only a ScrollView scrolls; visible (the default) lets children paint past the container, as in RN.

Visual (routed to GTK CSS)​

  • backgroundColor — supported: background-color.
  • opacity — supported: opacity, clamped to [0, 1].
  • boxShadow — supported: box-shadow, from either RN form — a CSS string or a BoxShadowValue[] array. A string is parsed rather than forwarded, so colors go through the same color parser (a PlatformColor works inside a shadow) and a malformed shadow is dropped with one development warning instead of corrupting the declaration block. Lengths follow RN's own grammar — a bare number or px, nothing else; blur may not be negative. Differs from react-native: an omitted color renders as black, not currentColor — RN's own documented deviation from CSS, kept here on purpose. Shadow order is CSS's: the first one paints on top.
  • outlineWidth — supported: outline-width; an unset outlineStyle becomes solid automatically once the width is greater than 0 (GTK, like the web, otherwise defaults to none). Takes no layout space, so unlike borderWidth it never reaches Yoga.
  • outlineColor / outlineOffset / outlineStyle — supported: outline-color / outline-offset (px, negative allowed) / outline-style (solid/dotted/dashed); an explicit style always wins over the automatic solid.
  • borderWidth — supported: border-width; an unset borderStyle becomes solid automatically once any border width is greater than 0 (GTK otherwise defaults to none).
  • borderTopWidth / borderRightWidth / borderBottomWidth / borderLeftWidth — supported: per-side border-*-width, emitted after the shorthand and overriding it; each also triggers the automatic solid style.
  • borderColor — supported: border-color; with no width the border stays invisible, since the default width is 0, as in RN.
  • borderTopColor / borderRightColor / borderBottomColor / borderLeftColor — supported: per-side border-*-color, emitted after the shorthand and overriding it.
  • borderStyle — supported: border-style (solid/dotted/dashed); an explicit value wins over the automatic solid.
  • borderRadius — supported: border-radius.
  • borderTopLeftRadius / borderTopRightRadius / borderBottomRightRadius / borderBottomLeftRadius — supported: per-corner border-*-radius, emitted after the shorthand and overriding it.
  • color — supported: color.
  • fontFamily — supported: font-family (a name containing spaces is quoted).
  • fontSize — supported: font-size, in px.
  • fontStyle — supported: font-style.
  • fontWeight — supported: font-weight (both keyword and numeric-string forms, "100"–"900").
  • letterSpacing — supported: letter-spacing, in px.
  • lineHeight — partial: line-height, in px (GTK ≥ 4.6). Matches RN's "line height in points" semantics; RN's multiplier form is not supported.
  • textAlign — partial: applied by Text directly rather than through CSS, since GTK4 CSS has no text-align — resolved to a label's own xalign/justification properties.
  • textDecorationLine — partial: applied by Text directly rather than through CSS, since GTK4 has no widget-level text-decoration — resolved to Pango's own underline/strikethrough attributes, which also reserve room below the baseline for an underline where one is measured.
  • transform — partial: never reaches CSS (GTK4 has no widget transform property) — the array is folded into one matrix and handed to the container's own allocation. translateX/translateY, scale, scaleX, scaleY, rotate/rotateZ only; no 3D, no skew, no matrix, no transformOrigin — see Components.

Colors​

FormatStatusNote
named colors (CSS Color 4), transparentsupportednormalized to rgb()/rgba()
#rgb / #rgba / #rrggbb / #rrggbbaasupportednormalized to rgb()/rgba()
rgb() / rgba()supportedboth comma and space syntax (rgb(255 0 0 / 0.5)); channels as numbers or percentages
hsl() / hsla()supportedhue as a number or with deg; saturation/lightness strictly as percentages; converted to rgb()/rgba()
PlatformColor("accent-bg-color", ...)supportedresolves to var(--accent-bg-color, ...) — Adwaita theme variables (libadwaita ≥ 1.6); @name reaches a legacy GTK named color as the fallback
var(--...) / @name as a plain stringsupportedpassed through without normalization
an invalid stringignoredthe color parses to nothing; the declaration is dropped, with one development warning per distinct value

Not part of the style contract​

Any key outside LayoutStyle/VisualStyle/BehavioralStyle — elevation, filter, mixBlendMode, textTransform, tintColor, and the like — is accepted, warned about once per key, and dropped. pointerEvents and zIndex are BehavioralStyle: each is read by the component that implements the behavior, not by either half of this pipeline (see Components for both).