tui4s
Guide

Styles and theme

kyo-ui styles in the terminal, custom colour properties and the two built-in looks.
CounterStyles.scala
    /** The custom colours of the app, declared once for the whole tree: a
      * kyo-ui `Stylesheet.vars` block (CSS custom properties on `:root`). The
      * run gets it as its stylesheet (`TuiApp.stylesheet`, or the `stylesheet`
      * of `Headless.start`), and an element names a colour with
      * `Style.Color.variable`.
      */
    val colors: Stylesheet = Stylesheet.vars(
      "frame" -> "#64748b",
      "label" -> "#eab308",
      "count" -> "#22c55e",
    )

    val frame: Style.Color = Style.Color.variable("frame")
    val label: Style.Color = Style.Color.variable("label")
    val count: Style.Color = Style.Color.variable("count")

The app gives this stylesheet to the run: override def stylesheet = CounterStyles.colors in its TuiApp. An element names a colour with Style.Color.variable("frame").

Custom properties

kyo-ui declares a custom property only in a Stylesheet: vars for the root, scopedVars for a class, an id or a data attribute. The run takes the stylesheet from TuiApp.stylesheet, from Tui.run(options, sheet), or from the stylesheet of Headless.start. A value is #hex, rgb(), rgba(), transparent or var(--other, fallback). A name with no value gives no colour, and the log of the run has one warning for that name.

Looks

A look (tui4s.widgets.Theme) is one value for the terminal and the web: the colours of the widgets, and the font, the corners and the spacing of the web. Two looks are built in, Theme.terminal and Theme.web:

Theme.scala
    /** The native web look: the system font of the browser, light colours, the
      * dark colours under `prefers-color-scheme: dark`, and round corners.
      */
    val web: Theme = Theme(
      name = "web",
      colors = Palette(
        accent = "#2563eb",
        muted = "#6b7280",
        border = "#d1d5db",
        surface = "#ffffff",
        selection = "#dbeafe",
        success = "#15803d",
        warning = "#b45309",
        danger = "#dc2626",
        background = "#f8fafc",
        text = "#111827",
      ),
      dark = Present(
        Palette(
          accent = "#60a5fa",
          muted = "#9ca3af",
          border = "#374151",
          surface = "#1f2937",
          selection = "#1e3a8a",
          success = "#4ade80",
          warning = "#fbbf24",
          danger = "#f87171",
          background = "#111827",
          text = "#f3f4f6",
        ),
      ),
      font = Font(
        "system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif",
        16,
      ),
      corners = Corners.Rounded(6),
      spacing = 0.5,
    )

Theme.palette gives the colours that a terminal reads. Theme.stylesheet gives all of the look to a web page. The widgets read the --tui4s-* properties (--tui4s-accent, --tui4s-muted, --tui4s-border, --tui4s-surface, --tui4s-selection, --tui4s-success, --tui4s-warning, --tui4s-danger). Colors.defaults has a value for each one.

What the terminal shows

A terminal cell has a character, a foreground colour, a background colour and a few text styles. A style property that the terminal does not show (fontSize, hover, shadow, ...) gives one warning in the log of the run, once for each name. In a test, Headless.awaitLog gives the lines.

The package Scaladoc of tui4s lists the honored and the ignored properties. A test (StyleTableTest) keeps that list correct.

Copyright © 2026