style

package
v0.5.9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 6, 2026 License: MIT Imports: 4 Imported by: 0

Documentation

Overview

Package style is the stylesheet engine for visual components.

It is excluded from WebAssembly by `//go:build !wasm` so it can never reach the client binary.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Aspect added in v0.4.0

type Aspect uint8

Aspect is the aspect ratio for MediaBox containers.

const (
	AspectSquare Aspect = iota
	Aspect3x2
	Aspect4x3
	Aspect16x9
)

type ColumnWidth added in v0.4.0

type ColumnWidth uint8

ColumnWidth represents minimum column width for grids.

const (
	ColumnNarrow ColumnWidth = iota
	ColumnMedium
	ColumnWide
)

type Edge added in v0.5.0

type Edge uint8

Edge is a block-axis edge of a box.

const (
	EdgeTop Edge = iota
	EdgeBottom
)

type Elevation

type Elevation uint8

Elevation is the shadow elevation scale.

const (
	Flat Elevation = iota
	Raised
	Floating
	Popover
)

type IconSize added in v0.4.4

type IconSize uint8

IconSize is the square size scale for icon-sized parts. The steps are relative to the inherited font size, so an icon tracks the text it sits with.

const (
	IconSm IconSize = iota // inline with a line of text
	IconMd                 // a control's icon: button, field affix
	IconLg                 // a navigation rail or toolbar icon
)

type Motion added in v0.3.1

type Motion uint8

Motion is the transition scale. Duration is owned by CSS; here we only select the level.

const (
	MotionNone Motion = iota // no transition
	MotionFast               // immediate highlight: hover, focus
	MotionBase               // state change
	MotionSlow               // panel/overlay transition
)

type Option added in v0.4.0

type Option func(*rule)

Option is a visual option that configures a rule.

func Anchor added in v0.5.0

func Anchor() Option

Anchor makes the element the positioning reference for a Flyout inside it. It is the trigger's container — a menu, a combobox — and emits nothing but position: relative.

func Animate added in v0.3.1

func Animate(m Motion) Option

Animate applies a transition according to the motion scale.

func As added in v0.4.0

func As(s Surface) Option

As sets the surface decision (background, text, border, and radius default).

func Backdrop added in v0.3.0

func Backdrop(s Scope) Option

Backdrop removes the element from the normal flow and stretches it over its Scope.

Example
package main

import (
	"github.com/tinywasm/widget"
	"github.com/tinywasm/widget/style"
)

type myButton struct{}

func (b *myButton) WidgetName() widget.Name { return widget.Name("btn") }
func (b *myButton) WidgetKind() widget.Kind { return widget.Region }

func main() {
	btn := &myButton{}
	_ = style.For(btn).
		Part("overlay", style.Backdrop(style.Viewport), style.Veil())
}

func Center

func Center(max ...Size) Option

Center defines a centered column with an optional maximum size (defaults to Readable).

func CenterContent added in v0.5.0

func CenterContent() Option

CenterContent centers whatever the element contains, on both axes. A button holding nothing but an icon needs it: the icon is a replaced element with display: block, so the text-align a button carries by default does not move it and it sits against the leading edge.

func ChipBox added in v0.5.0

func ChipBox() Option

ChipBox gives the element the shared chip width, the box a legend or a badge occupies. Fixing it is what makes a column of chips line up instead of each one hugging its own text; the text itself is truncated by the component that renders it.

func ControlBox added in v0.5.0

func ControlBox() Option

ControlBox gives the element the shared control height, the rhythm every interactive row in the app is measured against — a list row, a form field. Pinning both to one token is what keeps them from drifting apart.

func Cover

func Cover() Option

Cover locks the frame to the viewport height and stacks its children vertically. It is the outermost frame of an application shell: use KeepSize() on the children that must not shrink (a header) and Fill() on the one that takes the remaining height. Do not nest one Cover inside another.

The height is definite, not a floor, so a Fill() descendant resolves against it and a HideOverflow() or Scroll() descendant actually clips. A shell whose content can exceed the viewport must therefore give that descendant Scroll(); otherwise the overflow is unreachable.

func Docked added in v0.5.0

func Docked(scope Scope, edge Edge, side Side, gap Space) Option

Docked pins the element inside a corner, above the content and out of the flow, at the widget kind's stacking layer. Use it for a control that must not cost the content a band of its own: a floating action button, a row's overflow menu.

Parent pins it to the corner of the nearest Anchor. Viewport pins it to the screen, so it stays put while the content behind it scrolls or swipes — and it disappears with the widget, because a fixed descendant of a display:none ancestor is not rendered either.

func Drawer added in v0.4.3

func Drawer(side Side, size Size) Option

Drawer anchors the element to one inline edge of the viewport, full height, at the widget kind's stacking layer. It is the slide-in panel of a mobile navigation; pair it with RevealedBy(widget.Open) to control visibility and with a sibling Backdrop(Viewport)+Veil() for the dimmed page behind it.

Drawer sets the element's width. Do NOT also pass Width() — Validate rejects it.

func EdgeToEdge added in v0.4.0

func EdgeToEdge() Option

EdgeToEdge has no border radius or margin: flush against parent container.

func Fill

func Fill() Option

Fill takes up the entire available height.

func FillCentered added in v0.4.0

func FillCentered() Option

FillCentered fills the container with a centered child.

func Flyout added in v0.5.0

func Flyout(side Side) Option

Flyout lifts the element out of the flow and hangs it under its Anchor, flush with the given inline edge, at the widget kind's stacking layer. Use it for a dropdown: left in the flow, an expanding menu pushes everything below it down and the list jumps under the pointer that opened it.

The nearest Anchor() ancestor is what it hangs from. Without one it falls back to whatever ancestor happens to be positioned.

func FontSize added in v0.4.0

func FontSize(ts TextSize) Option

FontSize sets the text size.

func FontWeight

func FontWeight(w Weight) Option

FontWeight sets the font weight.

func Glyph added in v0.5.0

func Glyph(s Surface) Option

Glyph colours what the element draws — its text and, through currentColor, its icons — with a surface's base colour, and leaves the background alone. It is the "tinted, not filled" treatment: a nav item that is merely available shows a coloured icon, the selected one gets the filled surface via As().

func Grid

func Grid(min ColumnWidth, gap Space) Option

Grid defines auto-fit + minmax without a fixed number of columns.

func Grow added in v0.5.0

func Grow() Option

Grow takes the free space along the inline axis and nothing else. It is the Row counterpart of Fill(): Fill() also claims `height: 100%`, which inside a Row resolves against the row and stretches the part into a full-height block. Use Grow() for the item in a Row that should push its siblings to the trailing edge.

func Hide added in v0.5.0

func Hide() Option

Hide removes the element. Its use is inside On(): a part that exists on wide screens and not on a phone keeps its base styling and is switched off for the one device, which OnlyOn cannot express — OnlyOn hides by default and reveals per device, the opposite direction.

func HideOverflow added in v0.4.0

func HideOverflow() Option

HideOverflow clips descendants (overflow: hidden).

func IconBox added in v0.4.4

func IconBox(s IconSize) Option

IconBox sizes a part as a square that never shrinks — the shape an icon needs. A bare <svg> with no width or height falls back to the replaced-element default of 300x150 and blows the layout apart, so every part that renders one must declare its box here.

func Interactive added in v0.4.0

func Interactive(s Surface) Option

Interactive applies s and derives its hover, focus, and press treatments.

Example
package main

import (
	"github.com/tinywasm/widget"
	"github.com/tinywasm/widget/style"
)

type myButton struct{}

func (b *myButton) WidgetName() widget.Name { return widget.Name("btn") }
func (b *myButton) WidgetKind() widget.Kind { return widget.Region }

func main() {
	btn := &myButton{}
	_ = style.For(btn).
		Root(style.Interactive(style.Primary))
}

func KeepSize added in v0.4.0

func KeepSize() Option

KeepSize does NOT reflow: maintains its size under any width.

func MasterDetail added in v0.5.0

func MasterDetail(detail Size) Option

MasterDetail turns a two-panel container into a horizontal scroll-snap strip for a narrow screen: the master list rests where the browser's default scroll position already is, and the detail sits beside it at `detail` of the strip's width, so a sliver of the list stays visible and the panel it came from is obvious. Swiping is a native scroll; snapping to the detail is a plain ScrollIntoView from the row handler.

The FIRST TWO element children are the panels, in the same DOM order a desktop Split uses: detail first, master second. Anything after them — a modal mount point, a portal anchor — is left alone, which is why this addresses them by position and not with :first-child/:last-child. The strip is laid out RTL so the master — the second child, given order 1 — lands at the start edge, which RTL puts on the right, exactly where scroll position 0 already rests. That is what removes the need for a scroll nudge at mount time, which this framework's component contract has no hook for. Each panel resets to LTR so only the outer strip's flow is mirrored, never the content.

func MediaBox added in v0.4.0

func MediaBox(a Aspect) Option

MediaBox defines a box of fixed aspect ratio.

func OnEdge added in v0.5.0

func OnEdge(edge Edge, side Side, block Space, inline Space) Option

OnEdge centres the element ON one of its Anchor's edge lines — half outside the box, half inside — the way a fieldset legend rides the border it labels.

block is the distance from the Anchor's border to the line being ridden: pass the Anchor's padding to ride the box that padding encloses, or SpaceNone to ride the Anchor's own border. inline is how far the chip is indented along that line. The straddle itself is exact at any font size or padding, because the element is shifted by half of its OWN rendered height rather than by a guessed length.

func Pad

func Pad(s Space) Option

Pad applies internal padding according to the space scale.

func PadEdge added in v0.5.0

func PadEdge(e Edge, s Space) Option

PadEdge pads one block edge only. Pad() is all four sides, which is the right default; this exists for the case where a fixed overlay covers the top of a panel and the content underneath has to start below it without gaining the same inset left and right.

func PadInline added in v0.5.1

func PadInline(s Space) Option

PadInline pads the inline axis (start and end) and nothing else. A chip whose height is contracted against another element — the fieldset legend matches the list badge — cannot take vertical padding, but its text still needs air at the sides; flush text against a filled chip edge reads as a bug, not as density.

func PushEnd added in v0.5.0

func PushEnd() Option

PushEnd sends the part to the trailing edge of its line. It is the companion of Grow(): Grow() absorbs the free space so the items after it are pushed out, PushEnd() moves the free space in front of a single item — the only way to keep something right-aligned once flex-wrap has dropped it onto a line of its own.

func Raise

func Raise(e Elevation) Option

Raise applies shadow elevation according to the elevation scale.

func RevealedBy added in v0.4.0

func RevealedBy(st widget.State) Option

RevealedBy binds hiding/showing the element to a widget State.

Example
package main

import (
	"github.com/tinywasm/widget"
	"github.com/tinywasm/widget/style"
)

type myButton struct{}

func (b *myButton) WidgetName() widget.Name { return widget.Name("btn") }
func (b *myButton) WidgetKind() widget.Kind { return widget.Region }

func main() {
	btn := &myButton{}
	_ = style.For(btn).
		Part("menu", style.RevealedBy(widget.Open))
}

func Round

func Round(rad Radius) Option

Round applies border radius according to the radius scale.

func Row

func Row(gap Space) Option

Row defines a horizontal flow that wraps when it does not fit.

func Scroll added in v0.4.0

func Scroll() Option

Scroll overflows internally instead of growing. Implies Fill().

func ScrollRow added in v0.4.0

func ScrollRow(gap Space) Option

ScrollRow defines a horizontal scrolling strip with scroll-snap.

func Sidebar(side Side, width RailWidth, gap Space) Option

Sidebar places a fixed-width rail beside a fluid content area. The rail keeps its width; the content takes everything else. Below the point where the content can no longer hold its minimum width the two reflow into a single column, with no media query involved.

The container MUST have exactly two element children. Which one is the rail is decided by side, not by DOM order: SideEnd makes the LAST child the rail.

func SlideDeck added in v0.5.3

func SlideDeck(m Motion) Option

SlideDeck apila a sus hijos en capas que ocupan el contenedor entero y muestra solo aquel que lleva el estado widget.Current; los demás quedan aparcados en el borde inline-start y entran deslizándose de izquierda a derecha cuando les toca.

Es la forma de cambiar de panel en un shell SIN crear un scroller: un contenedor de scroll-snap horizontal aquí encadena con el scroll-snap horizontal que un módulo pueda tener adentro, y el gesto de deslizar dentro del contenido termina cambiando de sección sola.

Todos los hijos siguen montados en el DOM. Ese es el trato: el estado decide cuál está en pantalla, nadie desmonta nada. El contenedor es el bloque contenedor de sus hijos, así que un Docked(Parent) dentro de un panel se resuelve contra SU panel — no hace falta Anchor() en el hijo, y ponerlo lo ROMPE: el position: relative de @layer widgets gana sobre el position: absolute que este flujo emite en @layer primitives.

m gobierna la duración del deslizamiento. MotionNone conmuta sin animación.

func Split

func Split(ratio SplitRatio, gap Space) Option

Split defines two panels that stack below their own width.

Example
package main

import (
	"github.com/tinywasm/widget"
	"github.com/tinywasm/widget/style"
)

type myButton struct{}

func (b *myButton) WidgetName() widget.Name { return widget.Name("btn") }
func (b *myButton) WidgetKind() widget.Kind { return widget.Region }

func main() {
	btn := &myButton{}
	_ = style.For(btn).
		Root(style.Split(style.SplitTwoThirds, style.Space3))
}

func Stack

func Stack(gap Space) Option

Stack defines a vertical rhythm with children at full width.

Example
package main

import (
	"github.com/tinywasm/widget"
	"github.com/tinywasm/widget/style"
)

type myButton struct{}

func (b *myButton) WidgetName() widget.Name { return widget.Name("btn") }
func (b *myButton) WidgetKind() widget.Kind { return widget.Region }

func main() {
	btn := &myButton{}
	_ = style.For(btn).
		Root(style.Stack(style.Space4))
}

func StartContent added in v0.5.0

func StartContent() Option

StartContent packs what the element contains against its leading edge. It is the counterpart of CenterContent, for the case where the same part is centred in one state and aligned in another — an icon alone in a narrow rail, icon and label once the rail expands.

func Veil added in v0.4.0

func Veil() Option

Veil fills the element with a translucent wash overlaying the surface. Only makes sense alongside Backdrop.

func Width

func Width(s Size) Option

Width applies the relative width (Size) to the rule.

type Radius

type Radius uint8

Radius is the border radius scale.

const (
	RadiusNone Radius = iota
	RadiusSm
	RadiusMd
	RadiusLg
	RadiusFull
)

type RailWidth added in v0.4.3

type RailWidth uint8

RailWidth is the closed scale for a Sidebar's fixed column.

const (
	RailNarrow RailWidth = iota // icon only
	RailWide                    // icon plus label
)

type Scope added in v0.3.0

type Scope uint8

Scope says what an overlay dimensions against.

const (
	// Parent covers the nearest positioned ancestor (position: absolute).
	Parent Scope = iota
	// Viewport covers the entire window (position: fixed).
	Viewport
)

type Sheet

type Sheet struct {
	// contains filtered or unexported fields
}

Sheet represents a scoped stylesheet for a widget.

func For added in v0.4.0

func For(w widget.Widget) *Sheet

For opens the styling block for a widget.

Example
package main

import (
	"fmt"

	"github.com/tinywasm/widget"
	"github.com/tinywasm/widget/style"
)

type myButton struct{}

func (b *myButton) WidgetName() widget.Name { return widget.Name("btn") }
func (b *myButton) WidgetKind() widget.Kind { return widget.Region }

func main() {
	btn := &myButton{}
	sheet := style.For(btn).
		Root(style.As(style.Primary))

	fmt.Println(sheet.Parts())
}
Output:
[]

func (*Sheet) Cue

func (s *Sheet) Cue(c widget.Cue, p widget.Part, opts ...Option) *Sheet

Cue defines the style for a part (or Root if p is "") when the browser has a cue.

func (*Sheet) CueWithin added in v0.5.0

func (s *Sheet) CueWithin(c widget.Cue, container, p widget.Part, opts ...Option) *Sheet

CueWithin styles a part while an ANCESTOR part carries a browser cue — `.n__container:hover .n__part`. Reach for Cue() first; this is only for the case where the trigger and the thing that reacts are different elements, such as a rail that shows its labels while the pointer is over it.

func (*Sheet) CueWithinHover added in v0.5.8

func (s *Sheet) CueWithinHover(c widget.Cue, container, p widget.Part, opts ...Option) *Sheet

CueWithinHover is CueWithin gated on the fine-pointer capability: the same descendant selector, emitted inside `@media (hover: hover)`. A touch tap fires `:hover` and synthetic mouse events, so a hover reveal that is not scoped this way misfires on a phone — the exact reason this variant exists.

func (*Sheet) On added in v0.4.3

func (s *Sheet) On(d css.Device, p widget.Part, opts ...Option) *Sheet

On defines the style for a part (or Root if p is "") only on the given viewport class. It is the single sanctioned way to vary a widget by device: the query strings live in tinywasm/css and are exhaustively tested there.

Reach for a flow primitive first — Split, Grid and Sidebar already reflow on their own. Use On only when the ARRANGEMENT itself differs, e.g. a nav rail that becomes a drawer.

func (*Sheet) OnlyOn added in v0.4.3

func (s *Sheet) OnlyOn(d css.Device, p widget.Part, opts ...Option) *Sheet

OnlyOn declares a part that exists on one viewport class and nowhere else: it is display:none by default and takes the given options only on d.

Use it for chrome that is genuinely device-specific — a hamburger button, a drawer's backdrop. If the element merely CHANGES between devices rather than disappearing, declare it with Part() and refine it with On().

func (*Sheet) Part

func (s *Sheet) Part(p widget.Part, opts ...Option) *Sheet

Part defines the style for an anatomical part of the widget.

func (*Sheet) Parts added in v0.4.0

func (s *Sheet) Parts() []widget.Part

func (*Sheet) Root

func (s *Sheet) Root(opts ...Option) *Sheet

Root defines the style for the root element of the widget.

func (*Sheet) StateAttrs added in v0.4.3

func (s *Sheet) StateAttrs() []fmt.KeyValue

func (*Sheet) Stylesheet

func (s *Sheet) Stylesheet() *css.Stylesheet

func (*Sheet) Validate added in v0.4.0

func (s *Sheet) Validate() []error

func (*Sheet) When

func (s *Sheet) When(st widget.State, p widget.Part, opts ...Option) *Sheet

When defines the style for a part (or Root if p is "") when the widget has a specific state.

type Side added in v0.4.3

type Side uint8

Side names which edge a Sidebar's rail or a Drawer's panel is anchored to. Logical, not physical: it follows writing direction.

const (
	SideStart Side = iota // inline-start — left in LTR
	SideEnd               // inline-end   — right in LTR
)

type Size

type Size uint8

Size is the relative size measurement.

const (
	Content  Size = iota // adjusts to its content
	Readable             // readable line length
	Third
	Half
	TwoThirds
	Most // 90% — leaves a sliver of what sits behind it
	Full // 100% of the container
)

type Space

type Space uint8

Space is the spacing scale: 8 steps mirroring --space-N.

const (
	SpaceNone Space = iota
	Space1
	Space2
	Space3
	Space4
	Space6
	Space8
	Space12
)

type SplitRatio added in v0.4.0

type SplitRatio uint8

SplitRatio is the flex-grow ratio for Split partitions.

const (
	SplitHalf SplitRatio = iota
	SplitTwoThirds
	SplitThreeQuarters
)

type Surface

type Surface uint8

Surface is a complete visual decision: background, text, and border resolved together.

const (
	Page Surface = iota
	Panel
	Inset
	Primary
	Secondary
	Highlight
	Accent
	Success
	Danger
	Subtle
	Inactive
)

func (Surface) String added in v0.4.0

func (s Surface) String() string

type TextSize

type TextSize uint8

TextSize is the typography size scale.

const (
	TextXs TextSize = iota
	TextSm
	TextBase
	TextLg
	TextXl
	Text2xl
)

type Weight

type Weight uint8

Weight is the font weight scale.

const (
	WeightRegular Weight = iota
	WeightMedium
	WeightBold
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL