Documentation
¶
Overview ¶
Package css is GoWebComponents' typed, type-safe CSS layer. The raw-CSS layer (Rule/value/prop/variant) is the foundation; the Tailwind-shaped utility engine (subpackage css/u) is a typed convenience built on top. Emission v1 is runtime <style> injection on wasm and an in-memory buffer (read back by SSR and tests) on native.
The two public entry points cross into the html package without any edits to it: New returns a Sheet (a fmt.Stringer that flows through html.ClassNames, ClassMap keys, SSR, and attribute strings) and Class returns an html.PropOption that delegates to the existing html.Class setter.
// today
Div(html.Class("flex gap-2 hover:bg-slate-900"), …)
// typed, same shape
Div(css.Class(css.Display.Flex, css.Gap(css.Px(8)), css.Hover(css.Bg(css.Slate900))), …)
Package css authoring guide.
Layers ¶
Layer 1 — typed raw CSS (the foundation). Typed properties and values fold into a hashed class:
class := css.New(
css.Display.Flex,
css.Gap(css.Px(8)),
css.Bg(css.Slate900),
css.Hover(css.Bg(css.Slate800)), // pseudo variant
css.Media(css.MinW(768), css.FlexDir.Row), // at-rule variant
)
// class is "c-…"; the compiled CSS is emitted once through the active Sink.
Layer 2 — Tailwind-shaped utilities (subpackage css/u), built on Layer 1. Every utility resolves against the active css.Theme and returns Layer-1 rules:
import "github.com/monstercameron/GoWebComponents/v5/css/u" css.New(u.Flex, u.Gap(3), u.Bg(u.Slate900), u.Md(u.Hover(u.FlexRow)...)...)
Crossing into html ¶
Two entry points cross into the html package with zero edits to it:
// css.Class is an html.PropOption — drop it into any shorthand call site. shorthand.Div(css.Class(css.Display.Flex, css.Gap(css.Px(8))), …) // css.New returns a Sheet (fmt.Stringer) that flows through html.ClassNames, // ClassMap keys, SSR, and attribute strings. sheet := css.New(css.Display.Grid)
Dynamic values ¶
Runtime values would mint a new class per distinct value. Use Dynamic to keep a stable class that references a custom property and set the live value inline:
d := css.DynamicLength("--gap", "gap", state.Gap())
shorthand.Div(d.Class(), d.Style(), …)
SSR & hydration ¶
On native (SSR) the buffer sink collects every emitted rule. Serialize it into the head with css.StyleBlock(), which renders <style data-gwc-css="…">. On wasm hydration, css.SeedFromDocument() pre-seeds the registry from that block so already-present rules are recognized as hits and not re-injected.
Extension points ¶
- css.DefineUtility(name, rules…) — named reusable bundles (the plugin path).
- css.UseTheme(theme) — swap/extend the token scales the utility engine reads.
- css.DefineVariant(selectorTemplate) — new variant selectors via an "&" template.
- css.SetSink(sink) — custom emission targets without touching authoring.
Index ¶
- Variables
- func Class(parts ...any) html.PropOption
- func CriticalCSS() string
- func DeclareLayers(parseNames ...string)
- func DefineVariant(selectorTemplate string) func(...Rule) []Rule
- func EmitThemeTokens(parseTheme Theme)
- func Global(parseSelector string, parseRules ...Rule)
- func Harvest() string
- func HarvestedClasses() []string
- func Inject(parseID string, parseCSS string)
- func LayerGlobal(parseName string, parseSelector string, parseRules ...Rule)
- func Preflight()
- func PreflightInLayer(parseLayer string)
- func Reset()
- func Root(parseRules ...Rule)
- func Seed(parseClasses ...string)
- func SeedFromDocument()
- func StyleBlock() string
- func UseTheme(parseTheme Theme)
- type Angle
- type BgSizeValue
- type Color
- type ColorStop
- type Duration
- type Dynamic
- type Easing
- type FontStack
- type Frame
- type GradientDirection
- type GradientShape
- type GridPlacement
- type Image
- func ConicGradient(from Angle, x, y Length, stops ...ColorStop) Image
- func LinearGradient(a Angle, stops ...ColorStop) Image
- func LinearGradientTo(dir GradientDirection, stops ...ColorStop) Image
- func RadialGradient(shape GradientShape, stops ...ColorStop) Image
- func RawImage(parseValue string) Image
- func RepeatingLinearGradient(dir GradientDirection, stops ...ColorStop) Image
- func RepeatingRadialGradient(shape GradientShape, stops ...ColorStop) Image
- func URLImage(parsePath string) Image
- type Length
- func BreakpointValue(parseName string) (Length, bool)
- func Ch(n float64) Length
- func Clamp(min, preferred, max Length) Length
- func Ems(n float64) Length
- func FontSizeValue(parseName string) (Length, bool)
- func MaxLen(values ...Length) Length
- func MinLen(values ...Length) Length
- func Percent(n float64) Length
- func Px(n int) Length
- func RadiusValue(parseName string) (Length, bool)
- func RawLength(parseValue string) Length
- func Rem(n float64) Length
- func SpacingValue(parseIndex int) Length
- func VarLength(parseName string) Length
- func Vh(n float64) Length
- func Vw(n float64) Length
- type LineStyle
- type MediaQuery
- type NthArg
- type Number
- type Rule
- func Active(rules ...Rule) []Rule
- func Adjacent(target Selector, rules ...Rule) []Rule
- func After(rules ...Rule) []Rule
- func Animation(duration Duration, timing Easing) Rule
- func Before(rules ...Rule) []Rule
- func Bg(c Color) Rule
- func BgImage(images ...Image) Rule
- func BgPosition(x, y Length) Rule
- func BgSize(sizes ...BgSizeValue) Rule
- func Border(width Length, c Color) Rule
- func BorderBottom(width Length, c Color) Rule
- func BorderBottomStyle(s LineStyle) Rule
- func BorderColor(c Color) Rule
- func BorderLeft(width Length, c Color) Rule
- func BorderLeftStyle(s LineStyle) Rule
- func BorderRight(width Length, c Color) Rule
- func BorderRightStyle(s LineStyle) Rule
- func BorderSpacing(v Length) Rule
- func BorderStyle(s LineStyle) Rule
- func BorderTop(width Length, c Color) Rule
- func BorderTopStyle(s LineStyle) Rule
- func BorderWidth(v Length) Rule
- func BorderX(width Length, c Color) Rule
- func BorderY(width Length, c Color) Rule
- func Bottom(v Length) Rule
- func Child(target Selector, rules ...Rule) []Rule
- func ColumnGap(v Length) Rule
- func Custom(parseName string, parseValue string) Rule
- func CustomAngle(parseName string, parseValue Angle) Rule
- func CustomColor(parseName string, parseValue Color) Rule
- func CustomDuration(parseName string, parseValue Duration) Rule
- func CustomFontStack(parseName string, parseValue FontStack) Rule
- func CustomLength(parseName string, parseValue Length) Rule
- func CustomNumber(parseName string, parseValue Number) Rule
- func CustomShadow(parseName string, parseValue ShadowToken) Rule
- func DataTheme(parseName string, parseRules ...Rule) []Rule
- func DefineUtility(parseName string, rules ...Rule) []Rule
- func Descendant(target Selector, rules ...Rule) []Rule
- func Disabled(rules ...Rule) []Rule
- func FirstChild(rules ...Rule) []Rule
- func Flex(grow, shrink Number, basis Length) Rule
- func FlexBasis(v Length) Rule
- func FlexGrow(n Number) Rule
- func FlexShrink(n Number) Rule
- func Focus(rules ...Rule) []Rule
- func FocusVisible(rules ...Rule) []Rule
- func Font(stack FontStack) Rule
- func FontSize(v Length) Rule
- func Gap(v Length) Rule
- func GridArea(parseName string) Rule
- func GridAreas(parseRows ...string) Rule
- func GridAutoColumns(tracks ...Track) Rule
- func GridAutoRows(tracks ...Track) Rule
- func GridCols(tracks ...Track) Rule
- func GridColumn(p GridPlacement) Rule
- func GridRow(p GridPlacement) Rule
- func GridRows(tracks ...Track) Rule
- func H(v Length) Rule
- func Has(target Selector, rules ...Rule) []Rule
- func Hover(rules ...Rule) []Rule
- func Inset(v Length) Rule
- func InsetX(v Length) Rule
- func InsetY(v Length) Rule
- func Is(targets []Selector, rules ...Rule) []Rule
- func Keyframes(parseName string, frames ...Frame) Rule
- func LastChild(rules ...Rule) []Rule
- func Left(v Length) Rule
- func LineHeight(n Number) Rule
- func LineHeightLen(v Length) Rule
- func Margin(v Length) Rule
- func MarginX(v Length) Rule
- func MarginY(v Length) Rule
- func MarkImportant(parseRule Rule) Rule
- func MaskImage(images ...Image) Rule
- func MaskSize(sizes ...BgSizeValue) Rule
- func MaxHeight(v Length) Rule
- func MaxWidth(v Length) Rule
- func Media(query MediaQuery, rules ...Rule) []Rule
- func MinHeight(v Length) Rule
- func MinWidth(v Length) Rule
- func Not(target Selector, rules ...Rule) []Rule
- func NthChild(arg NthArg, rules ...Rule) []Rule
- func NthOfType(arg NthArg, rules ...Rule) []Rule
- func Opacity(n float64) Ruledeprecated
- func OpacityNum(n Number) Rule
- func Order(parseN int) Rule
- func Outline(width Length, c Color) Rule
- func OutlineOffset(v Length) Rule
- func OutlineStyle(s LineStyle) Rule
- func Padding(v Length) Rule
- func PaddingX(v Length) Rule
- func PaddingY(v Length) Rule
- func Property(parseName, parseValue string) Ruledeprecated
- func Raw(parseProperty, parseValue string) Rule
- func Right(v Length) Rule
- func Rounded(v Length) Rule
- func RoundedBottom(v Length) Rule
- func RoundedLeft(v Length) Rule
- func RoundedRight(v Length) Rule
- func RoundedTop(v Length) Rule
- func RowGap(v Length) Rule
- func Rules(parts ...any) []Rule
- func ScrollPadding(v Length) Rule
- func ScrollPaddingTop(v Length) Rule
- func Shadow(token ShadowToken) Rule
- func Sibling(target Selector, rules ...Rule) []Rule
- func TextColor(c Color) Rule
- func TextDecorationColor(c Color) Rule
- func TextDecorationThickness(v Length) Rule
- func TextIndent(v Length) Rule
- func TextOverflowEllipsis() Rule
- func TextUnderlineOffset(v Length) Rule
- func Top(v Length) Rule
- func Tracking(v Length) Rule
- func Transform(fns ...TransformFn) Rule
- func Transition(property TransitionProperty, duration Duration, easing Easing) Rule
- func TransitionDuration(duration Duration) Rule
- func TransitionLonghands(property TransitionProperty, duration Duration, easing Easing) Rule
- func Utility(parseName string) (rules []Rule, ok bool)
- func W(v Length) Rule
- func WhenDisabled(rules ...Rule) []Ruledeprecated
- func Within(parseAncestor string, parseRules ...Rule) []Rule
- func WordSpacing(v Length) Rule
- func ZIndex(n int) Rule
- type Selector
- type ShadowToken
- type Sheet
- type Sink
- type Theme
- type Track
- type TransformFn
- type TransitionProperty
Constants ¶
This section is empty.
Variables ¶
var ( Overflow = overflowNamespace("overflow") OverflowX = overflowNamespace("overflow-x") OverflowY = overflowNamespace("overflow-y") )
Overflow / OverflowX / OverflowY are the typed namespaces for the overflow properties: css.OverflowY.Auto.
Accessibility note: a box with Overflow.Auto or .Scroll is a scroll container, and a scroll container that is not focusable cannot be scrolled by keyboard. Pair it with html.Props{TabIndex: html.TabIndexZero} (see that field's comment).
var ( OverscrollBehavior = overscrollNamespace("overscroll-behavior") OverscrollBehaviorX = overscrollNamespace("overscroll-behavior-x") OverscrollBehaviorY = overscrollNamespace("overscroll-behavior-y") )
OverscrollBehavior / -X / -Y are the typed namespaces for overscroll-behavior. Contain stops a scroll that reaches the end of this box from chaining to the page behind it (and suppresses pull-to-refresh) — the fix for a horizontally scrolling table that drags the whole document sideways.
var ( AlignSelf = selfAlignNamespace("align-self") JustifySelf = selfAlignNamespace("justify-self") )
AlignSelf / JustifySelf override the container's alignment for one item — how a grid child stops stretching to its row's full height (AlignSelf.Start) without the container losing stretch for everything else.
These use the CSS-Align `start`/`end` keywords rather than the flexbox-era `flex-start`/`flex-end` used by the older Items/Justify namespaces, because `flex-start` is not valid in a grid context while `start` works in both.
var AlignContent = contentAlignProp{
Normal: decl("align-content", "normal"),
Start: decl("align-content", "start"),
Center: decl("align-content", "center"),
End: decl("align-content", "end"),
Between: decl("align-content", "space-between"),
Around: decl("align-content", "space-around"),
Evenly: decl("align-content", "space-evenly"),
Stretch: decl("align-content", "stretch"),
Baseline: decl("align-content", "baseline"),
}
AlignContent distributes a multi-line flex container's lines, or a grid's rows, within the container's own height.
It gets its own namespace rather than reusing selfAlignNamespace because the value grammars genuinely differ: align-content accepts the space-* distributions but NOT `auto`, while align-self/justify-self accept `auto` and no distributions. Sharing one struct would have put a silently-invalid `AlignContent.Auto` in autocomplete, which is precisely the class of mistake a typed CSS layer exists to prevent.
var Appearance = appearanceProp{
Auto: decl("appearance", "auto"),
None: decl("appearance", "none"),
}
Appearance is the typed namespace for appearance. None strips the platform widget look from a control (the native <select> arrow, the iOS <input> inner shadow) so a design system can style one box primitive and share it across input and select. It is emitted unprefixed; every current browser supports the unprefixed property.
var BgClip = bgClipProp{ BorderBox: decl("background-clip", "border-box"), PaddingBox: decl("background-clip", "padding-box"), ContentBox: decl("background-clip", "content-box"), Text: Rule{ // contains filtered or unexported fields }, }
BgClip is the typed namespace for background-clip.
var BgOrigin = bgOriginProp{
BorderBox: decl("background-origin", "border-box"),
PaddingBox: decl("background-origin", "padding-box"),
ContentBox: decl("background-origin", "content-box"),
}
var BgRepeat = bgRepeatProp{
Repeat: decl("background-repeat", "repeat"),
NoRepeat: decl("background-repeat", "no-repeat"),
RepeatX: decl("background-repeat", "repeat-x"),
RepeatY: decl("background-repeat", "repeat-y"),
Round: decl("background-repeat", "round"),
Space: decl("background-repeat", "space"),
}
BgRepeat is the typed namespace for background-repeat: css.BgRepeat.RepeatX.
var BorderCollapse = borderCollapseProp{
Collapse: decl("border-collapse", "collapse"),
Separate: decl("border-collapse", "separate"),
}
BorderCollapse is the typed namespace for border-collapse. `collapse` is what makes a table's hairlines share a single line rather than doubling at every cell boundary — the difference between a printed manifest and a spreadsheet.
var ColorScheme = colorSchemeProp{
Normal: decl("color-scheme", "normal"),
Light: decl("color-scheme", "light"),
Dark: decl("color-scheme", "dark"),
LightDark: decl("color-scheme", "light dark"),
}
ColorScheme is the typed namespace for the color-scheme property.
var Cursor = cursorProp{
Auto: decl("cursor", "auto"),
Pointer: decl("cursor", "pointer"),
Default: decl("cursor", "default"),
Text: decl("cursor", "text"),
Move: decl("cursor", "move"),
NotAllowed: decl("cursor", "not-allowed"),
Wait: decl("cursor", "wait"),
Grab: decl("cursor", "grab"),
Grabbing: decl("cursor", "grabbing"),
}
Cursor is the typed namespace for the cursor property: css.Cursor.Pointer.
var Display = displayProp{
Block: decl("display", "block"),
InlineBlock: decl("display", "inline-block"),
Inline: decl("display", "inline"),
Flex: decl("display", "flex"),
InlineFlex: decl("display", "inline-flex"),
Grid: decl("display", "grid"),
None: decl("display", "none"),
}
Display is the typed namespace for the CSS display property: css.Display.Flex, css.Display.Grid, css.Display.None, …
var FlexDir = flexDirProp{
Row: decl("flex-direction", "row"),
RowRev: decl("flex-direction", "row-reverse"),
Col: decl("flex-direction", "column"),
ColRev: decl("flex-direction", "column-reverse"),
}
FlexDir is the typed namespace for flex-direction.
var FlexWrap = flexWrapProp{
Wrap: decl("flex-wrap", "wrap"),
NoWrap: decl("flex-wrap", "nowrap"),
WrapReverse: decl("flex-wrap", "wrap-reverse"),
}
FlexWrap is the typed namespace for flex-wrap.
var FontStyle = fontStyleProp{
Normal: decl("font-style", "normal"),
Italic: decl("font-style", "italic"),
Oblique: decl("font-style", "oblique"),
}
FontStyle is the typed namespace for font-style.
var FontVariantLigatures = fontVariantLigaturesProp{
Normal: decl("font-variant-ligatures", "normal"),
None: decl("font-variant-ligatures", "none"),
NoCommon: decl("font-variant-ligatures", "no-common-ligatures"),
Contextual: decl("font-variant-ligatures", "contextual"),
NoContextual: decl("font-variant-ligatures", "no-contextual"),
Discretionary: decl("font-variant-ligatures", "discretionary-ligatures"),
}
FontVariantLigatures is the typed namespace for font-variant-ligatures.
var FontVariantNumeric = fontVariantNumericProp{
Normal: decl("font-variant-numeric", "normal"),
TabularNums: decl("font-variant-numeric", "tabular-nums"),
}
var FontWeight = fontWeightProp{
Normal: decl("font-weight", "400"),
Medium: decl("font-weight", "500"),
Semibold: decl("font-weight", "600"),
Bold: decl("font-weight", "700"),
}
FontWeight is the typed namespace for font-weight.
var Items = alignProp{
Start: decl("align-items", "flex-start"),
Center: decl("align-items", "center"),
End: decl("align-items", "flex-end"),
Stretch: decl("align-items", "stretch"),
Baseline: decl("align-items", "baseline"),
}
Items is the typed namespace for align-items.
var Justify = justifyProp{
Start: decl("justify-content", "flex-start"),
Center: decl("justify-content", "center"),
End: decl("justify-content", "flex-end"),
Between: decl("justify-content", "space-between"),
Around: decl("justify-content", "space-around"),
}
Justify is the typed namespace for justify-content.
var JustifyItems = itemsAlignProp{
Normal: decl("justify-items", "normal"),
Start: decl("justify-items", "start"),
Center: decl("justify-items", "center"),
End: decl("justify-items", "end"),
Stretch: decl("justify-items", "stretch"),
Baseline: decl("justify-items", "baseline"),
}
JustifyItems is the container-side default for every item's justify-self.
var MaskRepeat = maskRepeatProp{
Repeat: maskRepeatRule("repeat"),
NoRepeat: maskRepeatRule("no-repeat"),
RepeatX: maskRepeatRule("repeat-x"),
RepeatY: maskRepeatRule("repeat-y"),
}
MaskRepeat is the typed namespace for mask-repeat.
var OverflowWrap = overflowWrapProp{
Normal: decl("overflow-wrap", "normal"),
Anywhere: decl("overflow-wrap", "anywhere"),
BreakWord: decl("overflow-wrap", "break-word"),
}
OverflowWrap is the typed namespace for overflow-wrap — the escape valve for an unbreakable token (a URL, a hash) that would otherwise overflow its container.
var PointerEvents = pointerEventsProp{
Auto: decl("pointer-events", "auto"),
None: decl("pointer-events", "none"),
}
PointerEvents is the typed namespace for pointer-events. None makes a box invisible to the mouse so clicks fall through to what is underneath — required for decorative overlays (a gradient scrim, a perforation strip) that must not eat the clicks of the content they sit over.
var Position = positionProp{
Static: decl("position", "static"),
Relative: decl("position", "relative"),
Absolute: decl("position", "absolute"),
Fixed: decl("position", "fixed"),
Sticky: decl("position", "sticky"),
}
Position is the typed namespace for the CSS position property.
var TableLayout = tableLayoutProp{
Auto: decl("table-layout", "auto"),
Fixed: decl("table-layout", "fixed"),
}
TableLayout is the typed namespace for table-layout. `fixed` sizes columns from the first row only (fast, predictable); `auto` measures all content.
var TextAlign = textAlignProp{
Left: decl("text-align", "left"),
Center: decl("text-align", "center"),
Right: decl("text-align", "right"),
Justify: decl("text-align", "justify"),
Start: decl("text-align", "start"),
End: decl("text-align", "end"),
}
TextAlign is the typed namespace for text-align: css.TextAlign.Right.
var TextDecoration = textDecorationProp{
None: decl("text-decoration-line", "none"),
Underline: decl("text-decoration-line", "underline"),
Overline: decl("text-decoration-line", "overline"),
LineThrough: decl("text-decoration-line", "line-through"),
}
TextDecoration is the typed namespace for text-decoration-line. It sets the LONGHAND, not the shorthand: the shorthand resets thickness and offset, so TextDecoration.Underline composed with TextDecorationThickness would have raced against declaration ordering. As longhands they compose unconditionally.
var TextDecorationStyle = textDecorationStyleProp{
Solid: decl("text-decoration-style", "solid"),
Double: decl("text-decoration-style", "double"),
Dotted: decl("text-decoration-style", "dotted"),
Dashed: decl("text-decoration-style", "dashed"),
Wavy: decl("text-decoration-style", "wavy"),
}
TextDecorationStyle is the typed namespace for text-decoration-style.
var TextTransform = textTransformProp{
None: decl("text-transform", "none"),
Uppercase: decl("text-transform", "uppercase"),
Lowercase: decl("text-transform", "lowercase"),
Capitalize: decl("text-transform", "capitalize"),
}
TextTransform is the typed namespace for text-transform.
var TextWrap = textWrapProp{
Wrap: decl("text-wrap", "wrap"),
NoWrap: decl("text-wrap", "nowrap"),
Balance: decl("text-wrap", "balance"),
Pretty: decl("text-wrap", "pretty"),
Stable: decl("text-wrap", "stable"),
}
TextWrap is the typed namespace for text-wrap. Unsupported values are ignored by older browsers, so these are safe progressive enhancement.
var UserSelect = selectProp{
None: decl("user-select", "none"),
Text: decl("user-select", "text"),
All: decl("user-select", "all"),
Auto: decl("user-select", "auto"),
}
Select is the typed namespace for user-select: css.UserSelect.None.
var VerticalAlign = verticalAlignProp{
Baseline: decl("vertical-align", "baseline"),
Top: decl("vertical-align", "top"),
Middle: decl("vertical-align", "middle"),
Bottom: decl("vertical-align", "bottom"),
TextTop: decl("vertical-align", "text-top"),
TextBottom: decl("vertical-align", "text-bottom"),
Sub: decl("vertical-align", "sub"),
Super: decl("vertical-align", "super"),
}
VerticalAlign is the typed namespace for vertical-align — the property that controls where a table cell's content sits when rows have unequal heights.
var WhiteSpace = whiteSpaceProp{
Normal: decl("white-space", "normal"),
NoWrap: decl("white-space", "nowrap"),
Pre: decl("white-space", "pre"),
PreWrap: decl("white-space", "pre-wrap"),
PreLine: decl("white-space", "pre-line"),
BreakSpaces: decl("white-space", "break-spaces"),
}
WhiteSpace is the typed namespace for white-space.
Functions ¶
func Class ¶
func Class(parts ...any) html.PropOption
Class is the unified PropOption entry point for Div(...)/shorthand argument lists — the typed analog of JSX's className/clsx. It accepts a mixed list of:
- string — a literal class name (migration / third-party / utility strings)
- Rule — a single typed rule
- []Rule — the slice returned by variants (Hover, Media, Child, …)
- Sheet — a pre-folded class from New
- []Sheet — several pre-folded classes
Typed rules are folded together into one hashed class via New; strings and Sheets pass through as class names. Everything is joined into the class attribute. Mixing is the whole point:
Div(Class("legacy-util", Display.Flex, Gap(Px(8)), Hover(Bg(Slate900)), someSheet))
Type-safety note: the compile-checked guarantees live in the rule builders (Display.Flex, Gap(Px(8)), …); the argument list is `...any` because the class attribute is an inherently stringy boundary (exactly like clsx). Unrecognized argument types are ignored.
func CriticalCSS ¶
func CriticalCSS() string
CriticalCSS returns the critical-CSS <style> block to inline into an SSR document head (CSS6). It is the extraction half of the author-in-Go / ship- inline pipeline: render the app under the native sink (which collects every emitted rule), call CriticalCSS to serialize it into the page, and on the client call SeedFromDocument so the same rules are recognized as already present and never re-injected. CriticalCSS is an alias of StyleBlock with the pipeline-oriented name; both return "" when nothing has been emitted.
func DeclareLayers ¶
func DeclareLayers(parseNames ...string)
DeclareLayers emits an `@layer a, b, c;` statement establishing layer order (earlier = lower precedence). Call it once at startup before other emissions so the order statement leads the stylesheet. Identical declarations dedupe.
css.DeclareLayers("base", "components", "overrides")
func DefineVariant ¶
DefineVariant returns a reusable variant function from a selector template containing a single "&" placeholder (e.g. ".group:hover &" for group-hover, or "&[data-open]" for a data-attribute state). It is the open extension point for new pseudo/combinator variants beyond the built-ins.
func EmitThemeTokens ¶
func EmitThemeTokens(parseTheme Theme)
EmitThemeTokens emits the theme's RootRules into :root in one call — the convenience form of css.Root(theme.RootRules()...).
func Global ¶
Global emits CSS rules under a literal, top-level selector — an element (`body`, `h3`), the universal selector (`*`), a `:root` token block, or a stable semantic class (`.nav-link`, `.bento`) that other markup or a runtime theme engine targets by name. Unlike New, the rules are NOT scoped under a generated hashed class: the selector you pass is emitted verbatim.
css.Global("body", css.Margin(css.Px(0)), css.Font(css.SansStack))
css.Global(".nav-link", css.Display.Flex, css.Hover(css.Bg(css.Slate800)))
Variants compose against the selector exactly as they do against `&` in New: the `&` placeholder is replaced by the literal selector, so css.Hover(...) under Global(".btn", ...) emits `.btn:hover { … }` and css.Descendant(h3, ...) emits `.btn h3 { … }`.
Emission is deduped process-wide on the (selector + rules) content, flows through the same Sink as New (so SSR StyleBlock/Harvest include it and the wasm DOM sink injects it), and is hardened against <style> breakout. Calling Global repeatedly with the same selector and rules is cheap and emits once.
func Harvest ¶
func Harvest() string
Harvest returns all CSS emitted into the native buffer sink so far, concatenated in emission order. SSR serializes this into a <style> block; tests assert on it.
Harvest reads the active sink only when it is the default buffer sink. If a test installed a custom sink via SetSink, harvest its own state instead.
func HarvestedClasses ¶
func HarvestedClasses() []string
HarvestedClasses returns the class names emitted into the native buffer sink, in emission order. Used to seed the client registry for hydration.
func Inject ¶
Inject installs an arbitrary CSS string as a managed <style> element, keyed by id and idempotent (the first call for an id wins; later calls for the same id are no-ops). It is the runtime counterpart to Global for CSS that must be a raw string rather than typed rules — `@font-face` blocks for user-uploaded fonts, a third-party widget's stylesheet, etc.
css.Inject("app-fonts", `@font-face{font-family:"My Font";src:url(...)}`)
On wasm it creates (once) a <style id="..."> in <head>; on native it records the CSS into the buffer sink so SSR/tests can read it back. The CSS is hardened against <style> breakout. To replace injected CSS, use a new id.
func LayerGlobal ¶
LayerGlobal emits global rules (element/:root/semantic-class selectors) inside a named cascade layer — the typed home for a light-theme override layer that must beat base rules by layer order rather than specificity hacks (CSS4).
css.LayerGlobal("overrides", `[data-theme="light"] .card`, css.Bg(css.White))
func Preflight ¶
func Preflight()
Preflight emits a small, modern CSS reset (a Tailwind-preflight-equivalent) as global rules (CSS5). It is opt-in — call it once at startup if you want the base layer managed by the framework instead of hand-maintained inline. Rules are deduped, hardened, and flow through the same sink as the rest of css, so they appear in SSR output and inject on wasm.
func main() { css.Preflight(); /* … */ }
To place the reset in a cascade layer (so app styles reliably win), see PreflightInLayer.
func PreflightInLayer ¶
func PreflightInLayer(parseLayer string)
PreflightInLayer emits the reset inside a named cascade layer (e.g. "base"), so it sits below component/override layers regardless of source order (CSS4+CSS5).
css.DeclareLayers("base", "components", "overrides")
css.PreflightInLayer("base")
func Reset ¶
func Reset()
Reset clears the registry and resets the active sink to the build default. For tests — it gives each test a clean process-wide registry.
func Root ¶
func Root(parseRules ...Rule)
Root emits a `:root { … }` block — the canonical home for a custom-property (design-token) palette authored in typed Go:
css.Root(
css.CustomColor("accent", css.Hex("4f46e5")), // --accent: #4f46e5
css.CustomLength("radius", css.Px(12)), // --radius: 12px
)
It is shorthand for Global(":root", rules...). Author custom properties with the Custom* constructors in custom.go: they normalize the name through the same helper Var uses, so a declaration and its css.Var("accent") reference cannot drift apart, and a missing "--" prefix is impossible rather than a silently dead declaration. (css.Raw("--accent", "#4f46e5") still works and is what these replace.)
A runtime theme engine can then override individual tokens with element.style.setProperty without regenerating any classes.
func Seed ¶
func Seed(parseClasses ...string)
Seed marks a class as already-present without emitting it. Client hydration uses it to pre-seed the registry from server-rendered class names so existing rules are recognized as hits and not re-injected.
func SeedFromDocument ¶
func SeedFromDocument()
SeedFromDocument is a no-op on native builds: there is no DOM/document to read a server-rendered <style data-gwc-css> block from. It exists for cross-target API parity so code that hydrates the client registry compiles on both targets (the wasm build does the real seeding).
func StyleBlock ¶
func StyleBlock() string
StyleBlock returns the harvested CSS wrapped in a <style data-gwc-css> element carrying the emitted class names in a data attribute. The SSR head includes this so styles are present on first paint and the client can pre-seed its registry to suppress re-injection. Returns "" when nothing has been emitted.
Types ¶
type BgSizeValue ¶
type BgSizeValue string
BgSizeValue is one background-size layer value.
const ( // BgCover scales the image to cover the box, cropping the overflow; // BgContain fits it entirely, leaving gaps. BgCover BgSizeValue = "cover" BgContain BgSizeValue = "contain" BgAuto BgSizeValue = "auto" )
func BgSizeXY ¶
func BgSizeXY(w, h Length) BgSizeValue
BgSizeXY is an explicit width/height tile size: BgSizeXY(Px(11), Px(7)) -> "11px 7px".
func (BgSizeValue) String ¶
func (v BgSizeValue) String() string
type Color ¶
type Color string
Color is a CSS color value. Use the curated token constants, Hex, or RGB/RGBA.
const ( Transparent Color = "transparent" CurrentCo Color = "currentColor" White Color = "#ffffff" Black Color = "#000000" Slate50 Color = "#f8fafc" Slate100 Color = "#f1f5f9" Slate200 Color = "#e2e8f0" Slate300 Color = "#cbd5e1" Slate400 Color = "#94a3b8" Slate500 Color = "#64748b" Slate600 Color = "#475569" Slate700 Color = "#334155" Slate800 Color = "#1e293b" Slate900 Color = "#0f172a" Sky400 Color = "#38bdf8" Sky500 Color = "#0ea5e9" Sky600 Color = "#0284c7" Red500 Color = "#ef4444" Red600 Color = "#dc2626" Green500 Color = "#22c55e" Amber500 Color = "#f59e0b" )
Curated v1 color tokens (a Tailwind-shaped slice of the default palette).
func ColorMix ¶
ColorMix blends two colors: ColorMix(Sky500, White, 20) is "20% Sky500, the rest White". pct is the share of the FIRST color and is clamped to [0,100].
Mixing happens in oklab, not sRGB, because sRGB interpolation runs through a muddy desaturated midpoint (the classic grey band halfway between blue and yellow) while oklab keeps perceived lightness and chroma steady. This is how a design system derives a hover tint or a disabled tone from ONE token instead of shipping a whole second palette — and because the mix resolves at paint time, it composes with var() tokens a runtime theme engine rewrites.
func ColorValue ¶
ColorValue resolves a color token name against the active theme; ok reports whether the token exists.
func Hex ¶
Hex builds a color from a hex string, tolerating a missing leading '#': Hex("0af") and Hex("#0af") both -> "#0af". As a typed constructor it is safe-by-construction: any non-hex characters are dropped, so an untrusted string can never inject CSS or break out (e.g. Hex("</style>") -> "#e"). An empty/all- invalid input falls back to "#000000".
func RGB ¶
RGB builds an rgb() color; channels are clamped to [0,255] (matching how RGBA clamps alpha) so the formatter emits canonical, in-range output.
type ColorStop ¶
type ColorStop string
ColorStop is one entry in a gradient's stop list. Build one with Stop, StopAt, StopSpan, or ColorHint.
func ColorHint ¶
ColorHint is a bare position between two stops that shifts the midpoint of the blend without introducing a third color.
func StopAt ¶
StopAt pins a color to a position along the gradient line: StopAt(White, Percent(40)).
type Duration ¶
type Duration string
Duration is a CSS time value (transition/animation timing). Build with Ms or S.
func RawDuration ¶
RawDuration is the escape hatch for a time value the unit constructors cannot express — notably the sub-millisecond "0.01ms" used to neutralize a transition under prefers-reduced-motion. 0.01ms rather than 0ms is deliberate there: it still fires transitionend, so code awaiting that event does not hang for exactly the users who asked for less motion.
func VarDuration ¶
type Dynamic ¶
type Dynamic struct {
// contains filtered or unexported fields
}
Dynamic pairs a static, hashed class that references a CSS custom property with the inline StyleVar PropOption that carries the live value. This is the static/runtime boundary: a rule built from a runtime value would mint a new class per distinct value and grow the registry unboundedly, so instead the class references var(--name) (one stable hashed class) and the per-element value is set inline.
d := css.Dynamic("--gap", "gap", state.Gap()) // state.Gap() is a css.Length
Div(d.Class(), d.Style(), …) // class is stable; value is live
Construct one with DynamicLength (typed Length value) or DynamicVar (any string value); there is no NewDynamic — the type-specific factories are the intended constructors.
func DynamicLength ¶
DynamicLength declares a class that sets parseProperty to var(--parseName), plus the live Length value to bind inline. parseName is normalized to a "--" custom property.
func DynamicVar ¶
DynamicVar builds a Dynamic for any property/value pair.
func (Dynamic) Class ¶
func (d Dynamic) Class() html.PropOption
Class returns the PropOption that applies the var-referencing class.
func (Dynamic) Rule ¶
Rule returns the static Layer-1 rule that references the custom property. Fold it into New alongside other rules, or use Class for a one-shot PropOption.
func (Dynamic) Style ¶
func (d Dynamic) Style() html.PropOption
Style returns the PropOption that sets the live custom-property value inline, keeping the class and value in sync per element.
type Easing ¶
type Easing string
Easing is a typed timing-function. Use the presets or CubicBezier.
func CubicBezier ¶
CubicBezier builds a typed cubic-bezier easing.
type FontStack ¶
type FontStack string
FontStack is a typed font-family value: an ordered fallback list, a var() reference to a token, or one of the built-in system stacks.
const ( SansStack FontStack = "ui-sans-serif,system-ui,-apple-system,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif" SerifStack FontStack = "ui-serif,Georgia,Cambria,'Times New Roman',Times,serif" MonoStack FontStack = "ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,'Liberation Mono','Courier New',monospace" )
The built-in stacks. font-family IS a comma-separated fallback list — that is its entire grammar, and unlike the transition shorthand nothing is appended after the list, so a plain comma join is correct. `ui-*` leads each stack so the browser can pick the platform UI face before falling back to named families.
func FontStackOf ¶
FontStackOf builds a fallback list from family names, quoting any name that needs it and dropping characters that could close the quote or end the declaration — so a family name from a user profile cannot inject CSS:
FontStackOf("Atlas Grotesk", "system-ui", "sans-serif")
-> "'Atlas Grotesk',system-ui,sans-serif"
func RawFontStack ¶
RawFontStack is the escape hatch for a family list the constructors do not cover.
func VarFontStack ¶
VarFontStack references a custom property holding a font stack — the typed sibling of Var/VarLength for the font-family position, so a design token flows into Font without dropping to Raw. Same name sanitizing as Var.
type Frame ¶
Frame is a single keyframe step: an offset (e.g. "0%", "from", "100%") and the rules applied at that offset.
type GradientDirection ¶
type GradientDirection string
GradientDirection is a typed `to <side>` gradient direction.
const ( ToTop GradientDirection = "to top" ToBottom GradientDirection = "to bottom" ToLeft GradientDirection = "to left" ToRight GradientDirection = "to right" ToTopLeft GradientDirection = "to top left" ToTopRight GradientDirection = "to top right" ToBottomLeft GradientDirection = "to bottom left" ToBottomRight GradientDirection = "to bottom right" )
type GradientShape ¶
type GradientShape string
GradientShape is the typed shape/position prefix of a radial gradient.
const ( Circle GradientShape = "circle" Ellipse GradientShape = "ellipse" )
func CircleAt ¶
func CircleAt(x, y Length) GradientShape
CircleAt / EllipseAt position the gradient's center: CircleAt(Percent(50), Percent(100)) -> "circle at 50% 100%".
func CircleSizedAt ¶
func CircleSizedAt(radius Length, x, y Length) GradientShape
CircleSizedAt gives the circle an explicit radius as well as a center.
func EllipseAt ¶
func EllipseAt(x, y Length) GradientShape
type GridPlacement ¶
type GridPlacement string
GridPlacement is a typed grid-column / grid-row value. Build one with GridLineAt, GridSpan, GridLineName, GridRange, or GridAuto.
const GridAuto GridPlacement = "auto"
GridAuto lets the auto-placement algorithm pick the track.
func GridLineAt ¶
func GridLineAt(parseN int) GridPlacement
GridLineAt names a numbered grid line. Negative indices count back from the end, so GridLineAt(-1) is the last line — the typed way to say "to the far edge" without knowing the column count.
func GridLineName ¶
func GridLineName(parseName string) GridPlacement
GridLineName references a named grid line (from a [name] entry in a track list).
func GridRange ¶
func GridRange(start, end GridPlacement) GridPlacement
GridRange combines a start and an end placement: GridRange(GridLineAt(1), GridLineAt(-1)) -> "1 / -1". The separator is a slash, not a comma; grid-column takes exactly one start/end pair, so there is no list to get wrong.
func GridSpan ¶
func GridSpan(parseN int) GridPlacement
GridSpan spans a number of tracks from wherever the item lands: GridSpan(2).
func (GridPlacement) String ¶
func (p GridPlacement) String() string
type Image ¶
type Image string
Image is a CSS <image> value: a gradient, a url(), or the none keyword. Build one with the gradient constructors or URLImage.
const NoImage Image = "none"
NoImage is the `none` keyword — the typed way to clear an inherited background-image.
func ConicGradient ¶
ConicGradient builds conic-gradient(from <angle> at <x> <y>, stops…) — pie/donut meters without SVG.
func LinearGradient ¶
LinearGradient builds linear-gradient(<angle>, stops…). The angle is the direction the gradient travels TOWARD, measured clockwise from "up": Deg(180) points down.
func LinearGradientTo ¶
func LinearGradientTo(dir GradientDirection, stops ...ColorStop) Image
LinearGradientTo builds linear-gradient(to <side>, stops…) — the keyword form, which unlike an angle stays correct when the box is not square.
func RadialGradient ¶
func RadialGradient(shape GradientShape, stops ...ColorStop) Image
RadialGradient builds radial-gradient(<shape>, stops…).
func RawImage ¶
RawImage is the escape hatch for an <image> value the constructors do not cover (image-set(), cross-fade(), a paint() worklet).
func RepeatingLinearGradient ¶
func RepeatingLinearGradient(dir GradientDirection, stops ...ColorStop) Image
RepeatingLinearGradient tiles a linear gradient's stop list — stripes, rules, ruled-paper backdrops.
func RepeatingRadialGradient ¶
func RepeatingRadialGradient(shape GradientShape, stops ...ColorStop) Image
RepeatingRadialGradient tiles a radial gradient — dot grids, and the half-circle perforation of a torn stub:
RepeatingRadialGradient(CircleAt(Percent(50), Percent(100)),
StopSpan(paper, Zero, RawLength("3.5px")),
StopAt(Transparent, RawLength("3.5px")))
type Length ¶
type Length string
Length is a CSS length/size value that carries its unit in the value text, not the type. Build one with Px, Rem, Em, Percent, or the Raw escape hatch.
const Auto Length = "auto"
Auto is the keyword length "auto".
const Full Length = "100%"
Full is "100%".
const Zero Length = "0"
Zero is "0".
func BreakpointValue ¶
BreakpointValue resolves a responsive breakpoint name to its min-width.
func Ch ¶
Ch is a character-width length: Ch(68) -> "68ch". One ch is the advance width of the "0" glyph in the element's own font, so a ch max-width tracks the measure of the text (the ~45-75 character line that reads comfortably) instead of a pixel guess that drifts every time the font size changes.
func Clamp ¶
Clamp builds clamp(min, preferred, max) — one fluid value instead of a media-query staircase. The preferred term is normally viewport-relative (Vw) so it scales, with min/max as the hard stops:
Clamp(Rem(1), Vw(2.5), Rem(1.5)) -> clamp(1rem,2.5vw,1.5rem)
Keep min <= max: an inverted pair is legal CSS but resolves to min, silently ignoring the preferred value.
func FontSizeValue ¶
FontSizeValue resolves a type-scale name against the active theme.
func MinLen ¶
MinLen / MaxLen build min()/max() over a list of lengths. The commas are function arguments, not a declaration-level list, so they are safe wherever a Length goes.
func RadiusValue ¶
RadiusValue resolves a rounding name against the active theme.
func RawLength ¶
RawLength is the escape hatch for any length string not covered by a unit constructor (e.g. "calc(100% - 8px)", "min(10px, 1rem)").
func SpacingValue ¶
SpacingValue resolves a spacing-scale index against the active theme, falling back to Tailwind's n*0.25rem formula for indices outside the curated map.
func VarLength ¶
VarLength / VarDuration / VarAngle / VarNumber are the typed siblings of Var for custom properties used in non-color positions, so a CSS variable flows into W/FontSize/Gap (Length), Transition/Animation (Duration), Rotate (Angle), or LineHeight/Opacity (Number) with full type safety instead of falling through to Raw(...). Same sanitizing as Var.
type LineStyle ¶
type LineStyle string
LineStyle is a typed border/outline line style.
const ( LineSolid LineStyle = "solid" LineDashed LineStyle = "dashed" LineDotted LineStyle = "dotted" LineDouble LineStyle = "double" LineGroove LineStyle = "groove" LineRidge LineStyle = "ridge" // LineNone removes the border and collapses its width to 0; LineHidden does the // same except in a collapsed table border conflict, where it wins outright. LineNone LineStyle = "none" LineHidden LineStyle = "hidden" )
type MediaQuery ¶
type MediaQuery string
Media is a media-query at-rule wrapper. Build the query with MinW/MaxW or pass a raw query string via RawMedia.
const ( Dark MediaQuery = "(prefers-color-scheme:dark)" Light MediaQuery = "(prefers-color-scheme:light)" )
Dark / Light are the prefers-color-scheme media queries.
const ( // ReducedMotion matches when the user has asked the OS to reduce animation // (Windows "Show animations", macOS "Reduce motion", GNOME/Android equivalents). // Motion under this query should be neutralized, not merely shortened. ReducedMotion MediaQuery = "(prefers-reduced-motion:reduce)" // MotionOK is the inverse — the explicit "no preference" state. Prefer gating // motion ON with MotionOK over gating it OFF with ReducedMotion when the // animation is decorative: the default then costs nothing for a user whose // preference is unknown. MotionOK MediaQuery = "(prefers-reduced-motion:no-preference)" // ContrastMore / ContrastLess match prefers-contrast. Under ContrastMore, raise // border and text contrast rather than adding decoration. ContrastMore MediaQuery = "(prefers-contrast:more)" ContrastLess MediaQuery = "(prefers-contrast:less)" // ForcedColors matches when the platform has substituted its own palette // (Windows High Contrast / forced-colors mode). Inside it, colors are overridden // by the UA, so the useful work is restoring structure the forced palette // erases — borders on elements that were distinguished only by background color, // and forced-color-adjust:none on the few places a brand color must survive. ForcedColors MediaQuery = "(forced-colors:active)" // ReducedTransparency and ReducedData round out the preference set. ReducedTransparency MediaQuery = "(prefers-reduced-transparency:reduce)" ReducedData MediaQuery = "(prefers-reduced-data:reduce)" )
The accessibility preference queries. These are typed constants rather than RawMedia strings for a specific reason: a media query is not validated by anything. A typo in RawMedia("(prefers-reduced-motion: reduse)") does not fail to compile, does not fail to emit, and does not warn — it produces a syntactically valid @media block that simply never matches, so the accessibility accommodation silently does not exist. These three (plus MotionOK) are the a11y floor, so they are the ones that must be unmisspellable.
const ( HoverCapable MediaQuery = "(hover:hover)" NoHover MediaQuery = "(hover:none)" )
Hover / NoHover match the hover media feature — the correct test for "does this pointer have a hover state", as opposed to inferring it from viewport width. (Named HoverCapable/NoHover to avoid colliding with the Hover pseudo-class variant.)
const Print MediaQuery = "print"
Print matches paged output.
func MediaAll ¶
func MediaAll(queries ...MediaQuery) MediaQuery
MediaAll combines features with `and`, so every one must match:
MediaAll(MinW(768), Dark) -> "(min-width:768px) and (prefers-color-scheme:dark)"
Note this is `and`, not the comma that @media uses for `or`. A comma-joined query list would match if ANY feature matched, which is almost never what a caller nesting two conditions means — hence only the `and` form is provided typed.
func RawMedia ¶
func RawMedia(parseQuery string) MediaQuery
RawMedia is the escape hatch for an arbitrary media feature query.
type NthArg ¶
type NthArg string
NthArg is a typed argument to NthChild/NthOfType: Odd, Even, or AnB(a,b).
type Number ¶
type Number string
Number is a unitless CSS number (line-height, flex-grow, opacity factors, scale factors). Build with Num.
type Rule ¶
type Rule struct {
// contains filtered or unexported fields
}
Rule is one typed CSS declaration (or a small group of declarations) optionally wrapped in a variant scope (a pseudo-selector and/or one or more at-rules).
Rules are opaque values: build them with the typed property constructors (css.Gap, css.Bg, the css.Display namespace, …), wrap them with variants (css.Hover, css.Media, …), and fold a set of them into a single hashed class with css.New. A Rule carries no class identity of its own — identity is minted at New time from the canonical serialization of the folded rule-set.
func Animation ¶
Animation sets the animation shorthand timing for a Keyframes rule. Compose it alongside the Keyframes rule in the same New(...) call. It takes a typed Duration and Easing (matching Transition), so a unit-less or mistyped value is a compile error: Animation(Ms(200), Linear).
func Before ¶
Before / After scope to the ::before / ::after pseudo-elements. A content declaration defaults to "" when absent so the pseudo-element renders.
func BgImage ¶
BgImage sets background-image from one or more layers. background-image IS a comma-separated list of layers, first layer on top, and nothing is appended after it — so joining with commas is the correct grammar (contrast Transition, where the comma separates whole transitions and a bare property list is silently wrong).
There is deliberately NO Background() shorthand constructor in this package. The `background` shorthand is comma-separated per LAYER and each layer packs color/image/position/size/repeat/attachment/origin/clip in one slot; building it by concatenating a caller's image value with more tokens is exactly the defect class that made the old Transition emit dead CSS. Set background-color with Bg and the image/size/repeat/position longhands from here instead — as a bonus, a later rule can then override just the size without restating the image.
func BgPosition ¶
BgPosition sets background-position from typed offsets.
func BgSize ¶
func BgSize(sizes ...BgSizeValue) Rule
BgSize sets background-size, one value per BgImage layer (comma-separated list, same grammar note as BgImage).
func Border ¶
Border sets a solid border of the given width and color on all four sides. For a single edge use BorderTop/Right/Bottom/Left; for a non-solid line pair it with BorderStyle.
func BorderBottom ¶
func BorderBottomStyle ¶
func BorderColor ¶
BorderColor / BorderWidth set the color / width of all four sides without restating the whole shorthand.
func BorderLeft ¶
func BorderLeftStyle ¶
func BorderRight ¶
func BorderRightStyle ¶
func BorderSpacing ¶
BorderSpacing sets border-spacing (only meaningful under BorderCollapse.Separate).
func BorderStyle ¶
BorderStyle sets border-style for all four sides from a typed LineStyle.
func BorderTop ¶
BorderTop / BorderRight / BorderBottom / BorderLeft set one side's border to a solid line of the given width and color, matching Border's solid default:
BorderBottom(Px(1), Slate200) -> border-bottom: 1px solid #e2e8f0
For a non-solid line, pair a side constructor with BorderStyle (or the side-specific style namespaces): canonicalize sorts declarations by property name within a block, and "border-bottom" sorts before "border-bottom-style", so the longhand reliably overrides the shorthand it follows.
func BorderTopStyle ¶
BorderTopStyle / BorderRightStyle / BorderBottomStyle / BorderLeftStyle set one side's line style.
func BorderWidth ¶
func BorderX ¶
BorderX / BorderY set the horizontal / vertical border pairs as longhands, the same shape as PaddingX / MarginY.
func Custom ¶
Custom declares a custom property from a raw value string — the escape hatch for token values with no typed constructor (a font stack fragment, a `1px solid` line, a whole gradient). Only the VALUE is author-trusted; the NAME is still sanitized, so this is strictly safer than Raw("--"+name, value) and stays greppable.
func CustomAngle ¶
func CustomColor ¶
CustomColor / CustomLength / CustomNumber / CustomDuration / CustomAngle declare a custom property from a typed value. The name may be written with or without the leading "--" (both "accent" and "--accent" produce `--accent`).
func CustomDuration ¶
func CustomFontStack ¶
func CustomLength ¶
func CustomNumber ¶
func CustomShadow ¶
func CustomShadow(parseName string, parseValue ShadowToken) Rule
func DataTheme ¶
DataTheme is a convenience for Within(`[data-theme="<name>"]`, rules...) — the common ancestor-attribute theming case. (Named DataTheme to avoid colliding with the Theme token-config type.)
css.New(css.Bg(css.Slate900), css.DataTheme("light", css.Bg(css.White)))
func DefineUtility ¶
DefineUtility registers a named, reusable bundle of rules — the plugin path for user-defined utilities that compose with the built-ins. It returns the bundle so it can be used inline immediately, and stores it under name for later lookup via Utility.
card := css.DefineUtility("card",
css.Padding(css.Px(16)), css.Rounded(css.Px(8)), css.Bg(css.White))
Div(css.Class(card...), …)
func Descendant ¶
Descendant scopes rules to any descendant: & target.
func Disabled ¶
Disabled scopes rules to the :disabled pseudo-class. It uses the bare pseudo-class name like the other variants (Hover, Focus, Active, …).
func FirstChild ¶
FirstChild scopes rules to the :first-child structural pseudo-class.
func Flex ¶
Flex sets the flex shorthand from its three typed parts: grow, shrink, basis. The three-value form is spelled out on purpose — the one-value form (`flex: 1`) resets basis to 0%, which is a different layout from `flex: 1 1 auto`, and the difference is the single most common flexbox surprise.
Flex(Num(0), Num(0), Auto) -> flex: 0 0 auto // size to content, never flex Flex(Num(1), Num(1), Zero) -> flex: 1 1 0 // share space equally
func FlexShrink ¶
func FocusVisible ¶
FocusVisible scopes rules to :focus-visible.
func Font ¶
Font sets font-family from a typed stack: css.Font(css.SansStack).
There is deliberately NO `font` shorthand constructor. The `font` shorthand RESETS every font longhand it omits (line-height included) and ends in a comma-separated family list, which makes it both destructive and the same comma hazard the Transition grammar note describes. Use Font + FontSize + FontWeight + LineHeight.
func GridAreas ¶
GridAreas sets grid-template-areas from one quoted string per row:
GridAreas("rail head", "rail body") ->
grid-template-areas: "rail head" "rail body"
The rows are whitespace-separated quoted strings, not a comma list. Each row is sanitized to area-name characters (letters, digits, '-', '_', '.', and spaces) so a quote in a row string cannot terminate the string and inject a declaration; '.' survives because it is grid's own "empty cell" token. Rows are NOT padded or validated for equal cell counts — a ragged template is invalid CSS and the browser drops the whole declaration, which is the loud failure you want.
func GridAutoColumns ¶
func GridAutoRows ¶
GridAutoRows / GridAutoColumns size the implicit tracks the grid creates for items beyond the explicit template.
func GridCols ¶
GridCols / GridRows set grid-template-columns / grid-template-rows from a typed track list:
GridCols(TrackLen(Rem(14)), MinMax(TrackLen(Zero), Fr(1))) -> grid-template-columns: 14rem minmax(0,1fr)
func GridColumn ¶
func GridColumn(p GridPlacement) Rule
GridColumn / GridRow place an item on the column / row axis.
GridColumn(GridRange(GridLineAt(1), GridLineAt(-1))) // full-bleed row GridRow(GridSpan(2)) // two rows tall
func GridRow ¶
func GridRow(p GridPlacement) Rule
func Inset ¶
Inset sets all four offsets at once (`inset: 0` is the "fill the positioned ancestor" idiom).
func InsetX ¶
InsetX / InsetY set the horizontal / vertical offset pairs as longhands, the same shape as PaddingX / MarginY. They are emitted as physical longhands rather than `inset-inline`/`inset-block` so they do not flip under a right-to-left writing mode — matching PaddingX/MarginX, which are physical too.
func Keyframes ¶
Keyframes registers an @keyframes animation built from frames and returns a Rule that both carries the (deduped, content-named) @keyframes block and sets animation-name to it, so applying the rule animates the element. duration and timing are applied via the returned rule's shorthand.
func LineHeight ¶
LineHeight sets line-height from a typed Number (unitless) or Length.
func LineHeightLen ¶
LineHeightLen sets line-height from a typed Length.
func MarkImportant ¶
MarkImportant returns a copy of the rule with "!important" appended to every declaration value (idempotent). It is the typed analog of Tailwind's "!" modifier.
func MaskImage ¶
MaskImage sets mask-image from the same typed Image values the gradients produce — the other half of the signature-device toolkit, where a gradient decides not what is painted but what survives. A fade-out edge on a scroll container, a torn paper edge, an icon tinted by currentColor: all of them are "paint a solid, mask it with a gradient", which needs no image asset and inverts with the theme for free.
MaskImage(LinearGradientTo(ToBottom, Stop(Black), Stop(Transparent)))
Both the -webkit- longhand and the standard property are emitted: Safari still requires the prefix, and canonicalize sorts "-webkit-mask-image" before "mask-image", so the standard property always wins where it is supported.
func MaskSize ¶
func MaskSize(sizes ...BgSizeValue) Rule
MaskSize / MaskRepeat mirror BgSize / BgRepeat for the mask layer.
func Media ¶
func Media(query MediaQuery, rules ...Rule) []Rule
Media scopes rules inside an @media at-rule.
func Order ¶
Order overrides a flex/grid item's visual position. It is deliberately separate from the DOM order it overrides: reordering visually without reordering the DOM desynchronizes tab order from reading order, so use it only where both still agree.
func OutlineOffset ¶
OutlineOffset sets outline-offset from a typed Length.
func OutlineStyle ¶
func Raw ¶
Raw is the explicit declaration escape hatch for any property/value not covered by a typed constructor: css.Raw("backdrop-filter", "blur(4px)"). Intentionally named so it is greppable / lint-gateable; prefer a typed constructor.
func RoundedBottom ¶
func RoundedLeft ¶
func RoundedRight ¶
func RoundedTop ¶
RoundedTop / RoundedBottom / RoundedLeft / RoundedRight round one edge's pair of corners — the "tab" and "card stub" shapes, which Rounded (all four) cannot express.
func Rules ¶
Rules flattens a mix of single Rules and rule slices (the []Rule returned by variant helpers) into a flat []Rule, so authoring can freely intermix them:
css.New(css.Rules(
css.Display.Flex,
css.Hover(css.Bg(css.Slate800)), // []Rule
css.Gap(css.Px(8)),
)...)
func ScrollPadding ¶
ScrollPadding / ScrollPaddingTop inset the scrollport for scroll-snapping and fragment/focus jumps — how a sticky header stops covering the element that a same-page anchor just scrolled to.
func ScrollPaddingTop ¶
func TextDecorationColor ¶
TextDecorationColor sets the line color independently of the text color.
func TextDecorationThickness ¶
TextDecorationThickness / TextUnderlineOffset tune an underline's weight and distance from the baseline — the difference between a link underline that reads as typography and one that reads as a browser default.
func TextOverflowEllipsis ¶
func TextOverflowEllipsis() Rule
TextOverflowEllipsis truncates overflowing text with an ellipsis. It only takes effect on a single-line, non-wrapping, overflow-hidden box, so all three declarations are emitted together — the property on its own is a silent no-op, and that is the most common reason "text-overflow: ellipsis doesn't work".
func TextUnderlineOffset ¶
func Top ¶
Top / Right / Bottom / Left set a single positioning offset. Negative values come from the Length constructors (Px(-1)), so nothing here has to parse a sign.
func Transform ¶
func Transform(fns ...TransformFn) Rule
Transform builds the transform property from one or more typed transform fns.
func Transition ¶
func Transition(property TransitionProperty, duration Duration, easing Easing) Rule
Transition builds a typed transition shorthand: property, duration, easing.
GRAMMAR — DO NOT "simplify" the expansion below back into a concatenation. The `transition` shorthand is a comma-separated list of *whole transitions*, not a property list followed by shared timing:
transition: <prop> <dur> <ease>, <prop> <dur> <ease>, …
So the naive `string(property)+" "+dur+" "+ease` is silently wrong the moment property holds more than one name. With PropColors it emitted
transition: color, background-color, border-color, fill, stroke 120ms ease
which the browser parses as FOUR transitions with the default 0s duration (`color`, `background-color`, `border-color`, `fill`) plus one 120ms transition on `stroke` — i.e. the preset animated nothing anybody could see. The comma belongs *between* transitions, so a property list has to be distributed over the duration/easing rather than pasted in front of them.
Emission therefore expands one transition per property:
Transition(PropOpacity, Ms(120), Ease) -> transition:opacity 120ms ease
Transition(PropColors, Ms(120), Ease) -> transition:color 120ms ease,
background-color 120ms ease, … (5 total)
The single-property case is byte-identical to the old output, so class hashes for single-property transitions are unchanged. (The longhand alternative — transition-property/-duration/-timing-function — is equally correct CSS but would have changed every single-property class hash, so the shorthand expansion wins.) Commas nested inside functional values (cubic-bezier(...), rgba(...)) are not list separators and are preserved; see splitCommaList.
func TransitionDuration ¶
TransitionDuration sets transition-duration on its own — the typed path for a reduced-motion override that neutralizes motion without restating the property list (pair it with TransitionLonghands).
func TransitionLonghands ¶
func TransitionLonghands(property TransitionProperty, duration Duration, easing Easing) Rule
TransitionLonghands is the longhand form of Transition: transition-property / -duration / -timing-function as three declarations.
It exists for the case where a later rule (a reduced-motion override, say) wants to replace ONLY the duration: canonicalize folds declarations by property name within a scope, so an override of `transition-duration` beats the longhand but cannot reach inside the `transition` shorthand's single value. Prefer Transition unless you specifically need that.
func WhenDisabled
deprecated
func Within ¶
Within scopes rules to apply only when an ancestor matches selector — the `<ancestor> &` form that powers attribute-state theming (`[data-theme="light"] &`, `html[data-density="compact"] &`). It is the ancestor-state counterpart to the self-state variants (Hover/Focus/…):
css.New(css.Within(`[data-theme="light"]`, css.Bg(css.White), css.Color(css.Slate900)))
emits `[data-theme="light"] .c-xxx { … }`.
func WordSpacing ¶
WordSpacing sets word-spacing (letter-spacing is Tracking).
type Selector ¶
type Selector string
Selector is a typed CSS selector fragment used as the target of a combinator (Child/Descendant/…) or a functional pseudo-class (Not/Has/Is). Build one with the typed constructors — never a free string — so composition stays checkable.
func AttrEq ¶
AttrEq targets an attribute-equals selector: css.AttrEq("type","submit") -> `[type="submit"]`. The name is sanitized and the value is string-escaped so a crafted value cannot break out of the quotes and inject a live global rule.
func AttrSel ¶
AttrSel targets an attribute-presence selector: css.AttrSel("data-open") -> "[data-open]". The attribute name is sanitized to CSS-identifier-safe characters.
func ClassSel ¶
ClassSel targets a literal class name (interop with existing string classes): css.ClassSel("title") -> ".title". The name is sanitized to CSS-identifier-safe characters so it cannot inject additional selector/rule text.
func Sel ¶
Sel is the explicit selector-template escape hatch for a fragment the typed builders don't cover. The fragment is appended after the class anchor; use "&" only via DefineVariant for parent-context selectors. Greppable on purpose.
type ShadowToken ¶
type ShadowToken string
ShadowToken is a typed box-shadow value. Use the preset tokens or RawShadow.
const ( ShadowNone ShadowToken = "none" ShadowSm ShadowToken = "0 1px 2px 0 rgba(0,0,0,0.05)" ShadowMd ShadowToken = "0 4px 6px -1px rgba(0,0,0,0.1)" ShadowLg ShadowToken = "0 10px 15px -3px rgba(0,0,0,0.1)" ShadowXl ShadowToken = "0 20px 25px -5px rgba(0,0,0,0.1)" Shadow2xl ShadowToken = "0 25px 50px -12px rgba(0,0,0,0.25)" )
func RawShadow ¶
func RawShadow(parseValue string) ShadowToken
RawShadow is the escape hatch for a box-shadow value no preset token or ShadowOf call covers (a `drop-shadow`-style stack copied from a design tool, a currentColor ring, …): RawShadow("0 0 0 3px currentColor").
Named like RawLength/RawMedia so raw usage stays greppable. The value is emitted verbatim, so it is author-trusted CSS — see hardenCSS for what is (and is not) guaranteed about untrusted input.
func ShadowInset ¶
func ShadowInset(x, y, blur, spread Length, c Color) ShadowToken
ShadowInset is ShadowOf with the `inset` keyword (an inner shadow).
func ShadowOf ¶
func ShadowOf(x, y, blur, spread Length, c Color) ShadowToken
ShadowOf builds one shadow from typed parts: offset, blur, spread, color.
ShadowOf(Zero, Px(1), Px(2), Zero, RGBA(0,0,0,0.05)) -> "0 1px 2px 0 rgba(0,0,0,0.05)"
func Shadows ¶
func Shadows(tokens ...ShadowToken) ShadowToken
Shadows layers several shadows into one box-shadow value.
Unlike `transition`, box-shadow's comma-separated list IS a list of complete values with nothing appended after it, so joining tokens with a comma is the whole grammar — there is no per-item timing to distribute (contrast Transition). ShadowNone is not a list item; a "none" among several shadows makes the entire declaration invalid, so it is dropped here rather than emitted into the list.
func (ShadowToken) String ¶
func (parseToken ShadowToken) String() string
String returns the box-shadow value, matching the other typed CSS value types.
type Sheet ¶
type Sheet string
Sheet is a generated class name (or space-separated names). It satisfies fmt.Stringer, so it already flows through html.ClassNames(...), appendClassFragments, ClassMap keys, SSR, and attribute strings.
func Layer ¶
Layer folds rules into a hashed class emitted inside the named cascade layer (`@layer <name> { .c-xxx { … } }`), giving declared override precedence instead of registration-order accident (CSS4). Declare the layer order once with DeclareLayers so later layers reliably win.
css.DeclareLayers("base", "components", "overrides")
btn := css.Layer("components", css.Display.Flex, css.Padding(css.Px(8)))
func New ¶
New folds a rule-set into a single content-hashed class, registers it (deduped process-wide), and emits its compiled CSS through the active Sink exactly once. It is safe and cheap to call inside render loops: N identical New(...) calls produce one registry entry and one injected rule.
Variant helpers (css.Hover, css.Media, …) return []Rule; spread them into New with the ... operator, or pass them through the rules... variadic directly — New accepts both single Rules and rule slices via the Rules helper.
type Sink ¶
Sink is the documented emission seam. New(...) calls Emit exactly once per newly-registered class (the dedup happens before the sink is touched), so a Sink never sees the same class twice within one process. The runtime wasm sink appends to a managed <style> element; the native sink buffers for SSR/tests; a build-time extraction pass would be a third implementation.
type Theme ¶
type Theme struct {
// Spacing maps a scale index (Tailwind's 0,1,2,3,…) to a Length. The default
// follows Tailwind: index n -> n*0.25rem.
Spacing map[int]Length
// Colors maps a token name ("slate-900") to a Color.
Colors map[string]Color
// FontSizes maps a type-scale name ("sm","base","lg") to a Length.
FontSizes map[string]Length
// Breakpoints maps a responsive name ("sm","md","lg","xl","2xl") to its
// min-width Length and drives the responsive variants.
Breakpoints map[string]Length
// Radii maps a rounding name ("sm","md","lg","full") to a Length.
Radii map[string]Length
}
Theme is the typed analog of tailwind.config.js: the named scales the Layer-2 utility engine resolves against. Swap or extend it with UseTheme; utilities and responsive variants read the active theme.
func ActiveTheme ¶
func ActiveTheme() Theme
ActiveTheme returns a snapshot reference to the active theme.
func DefaultTheme ¶
func DefaultTheme() Theme
DefaultTheme returns Tailwind's default scales (the curated v1 subset).
func (Theme) RootRules ¶
RootRules returns the theme's scales as typed custom-property declarations (CSS2): --color-<name>, --space-<index>, --text-<name>, --radius-<name>. It is the bridge between the typed Theme (which the utility engine resolves at class-generation time) and a live CSS-variable palette: emit these into :root and reference them with Var, then a runtime element.style.setProperty reskins every reference without regenerating classes.
css.Root(css.DefaultTheme().RootRules()...) // :root palette
css.New(css.DataTheme("light", lightTheme.RootRules()...)) // a scoped theme
Breakpoints are intentionally omitted — they drive @media queries, where var() is not reliably supported.
type Track ¶
type Track string
Track is one entry in a grid track list (a column width or a row height). Build one with Fr, TrackLen, MinMax, Repeat, FitContent, or the keyword constants.
func FitContent ¶
FitContent builds fit-content(limit): size to content, but never past limit.
func Fr ¶
Fr is a fractional track: Fr(1) -> "1fr". The fr unit only exists inside a grid track list, which is why it is a Track constructor and not a Length one.
func MinMax ¶
MinMax builds minmax(min, max). The commas here are *function arguments*, not a track-list separator, so they are safe inside a joined track list.
MinMax(TrackLen(Zero), Fr(1)) -> minmax(0,1fr)
minmax(0,1fr) rather than a bare 1fr is the fix for a grid column that refuses to shrink below its content: 1fr's implicit minimum is auto (i.e. min-content).
func RepeatFill ¶
func RepeatFit ¶
RepeatFit / RepeatFill are repeat(auto-fit, …) / repeat(auto-fill, …): as many tracks as fit. auto-fit collapses the empty ones (so the filled tracks stretch), auto-fill keeps them (so the grid holds its rhythm). This is the whole no-media-query responsive-card-grid idiom:
GridCols(RepeatFit(MinMax(TrackLen(Rem(16)), Fr(1))))
type TransformFn ¶
type TransformFn string
TransformFn is a single typed transform function (Scale, Rotate, …). Compose several in one Transform call.
func TranslateX ¶
func TranslateX(v Length) TransformFn
TranslateX / TranslateY build translate functions from typed Lengths.
func TranslateY ¶
func TranslateY(v Length) TransformFn
type TransitionProperty ¶
type TransitionProperty string
TransitionProperty names one property — or a comma-separated LIST of properties (see PropColors) — for Transition. The All/Colors/Transform/Opacity presets cover the common cases; Prop wraps an arbitrary property name and TransitionProps composes several into a list.
const ( PropAll TransitionProperty = "all" PropColors TransitionProperty = "color, background-color, border-color, fill, stroke" PropOpacity TransitionProperty = "opacity" PropTransform TransitionProperty = "transform" PropShadow TransitionProperty = "box-shadow" )
func Prop ¶
func Prop(parseName string) TransitionProperty
Prop names an arbitrary transition property (typed wrapper, not a free arg).
func TransitionProps ¶
func TransitionProps(parseProps ...TransitionProperty) TransitionProperty
TransitionProps composes several properties into one comma-separated TransitionProperty list, the same shape as the PropColors preset:
css.Transition(css.TransitionProps(css.PropOpacity, css.PropTransform), css.Ms(120), css.Ease)
Transition expands the list correctly (one transition per property) — see the grammar note on Transition.