API reference: package tela
import "github.com/kuronosu/tela"This page is generated from the doc comments of the package; the same text is on pkg.go.dev. For guides and examples, start at the wiki home.
- Overview
- Constants
- Variables
- Functions:
Animate·Assets·BackgroundGradient·Bg·BgFn·BgImage·BorderColor·BorderWidth·Bottom·Bounce·Box·BoxShadow·C·CP·CreateContext·CubicBezier·Damping·DefaultTheme·DevMode·Duration·Ease·FontSize·FontWeight·Gap·Height·HeightFn·Hex·Initial·Left·LinearGradient·Main·MapValue·Margin·MaxHeight·MaxWidth·Memo·MergeProps·MinHeight·MinWidth·MustSVG·OKLCH·OnDone·Opacity·OpacityFn·OpenPath·OpenURL·Padding·PaddingXY·ParseSVG·Post·Quit·RGB·RGBA·Radius·Right·Rotate·Run·Scale·SetColorScheme·SetTheme·Spring·Stiffness·Stop·StopAt·StopPropagation·TextColor·TextColorFn·Toggle·Top·Translate·TranslateFn·UseBounds·UseCallback·UseColorScheme·UseContext·UseDirection·UseEffect·UseEffectDo·UseElementRef·UseGo·UseID·UseInterval·UseLayoutEffect·UseMemo·UseMount·UseOnce·UsePresence·UsePresenceTween·UseReducedMotion·UseReducer·UseRef·UseScroll·UseSize·UseSpring·UseState·UseStateSet·UseStateUpdate·UseTheme·UseTimeout·UseTween·UseUpdateEffect·UseValue·UseWindow·Velocity·WH·Width·WidthFn·WithKey·ZIndex - Types
type Animatabletype AnimationOption:Bounce·Damping·Duration·Ease·Initial·OnDone·Spring·Stiffness·Velocitytype Apptype Backdroptype Callback:UseCallback·Fn·IsZerotype ChangeEvent:DefaultPrevented·PreventDefault·StopPropagationtype Childtype Color:Hex·OKLCH·RGB·RGBA·Clamp·IsFinite·IsOpaque·MulAlpha·NRGBA8·Premul8·Premultiplied·String·ToOKLCH·ToOklab·WithAlphatype ColorScheme:UseColorScheme·Stringtype Componenttype CompositionEvent:DefaultPrevented·PreventDefault·StopPropagationtype Context:CreateContext·Providertype DevStatetype Dispatcher:UseReducer·Dispatchtype DragEvent:DefaultPrevented·PreventDefault·StopPropagationtype Easing:CubicBeziertype ElementRef:UseElementRef·Blur·Bounds·Click·Focus·Focused·ScrollBy·ScrollIntoView·ScrollOffset·ScrollTo·ScrollToIndex·Select·SelectionRange·SetSelectionRange·Valuetype FocusEvent:DefaultPrevented·PreventDefault·StopPropagationtype Gradient:LinearGradient·Painttype GradientStop:Stop·StopAttype Icon:MustSVG·ParseSVGtype InputEvent:DefaultPrevented·PreventDefault·StopPropagationtype KeyCodetype KeyLocation:Stringtype KeyNametype KeyboardEvent:DefaultPrevented·PreventDefault·StopPropagationtype MouseButton:Stringtype MouseButtons:Hastype MouseEvent:DefaultPrevented·PreventDefault·StopPropagationtype Node:C·CP·Memo·WithKey·Build·IsZero·Key·Stringtype Pointtype PointerEvent:DefaultPrevented·PreventDefault·StopPropagationtype PointerKind:Stringtype Preview:Buildtype Previews:Namestype Prop:MergeProps·Buildtype Rect:Bottom·Contains·Righttype Ref:UseReftype SchemeColortype ScrollAlign:Stringtype ScrollEvent:DefaultPrevented·PreventDefault·StopPropagationtype SelectEvent:DefaultPrevented·PreventDefault·StopPropagationtype Setter:UseState·IsZero·Set·Updatetype Shadowtype Sizetype StopHandler:StopPropagationtype StyleProp:BackgroundGradient·Bg·BgFn·BgImage·BorderColor·BorderWidth·Bottom·Box·BoxShadow·FontSize·FontWeight·Gap·Height·HeightFn·Left·Margin·MaxHeight·MaxWidth·MinHeight·MinWidth·Opacity·OpacityFn·Padding·PaddingXY·Radius·Right·Rotate·Scale·TextColor·TextColorFn·Top·Translate·TranslateFn·WH·Width·WidthFn·ZIndex·Build·Opstype SubmitEvent:DefaultPrevented·PreventDefault·StopPropagationtype Theme:DefaultThemetype ThemeValues:UseTheme·Color·FontMono·FontSans·Lookup·Radius·Scheme·Tokenstype TitleBarColorstype Value:UseBounds·UsePresenceTween·UseScroll·UseSize·UseSpring·UseTween·UseValue·Get·Latest·Set·Updatetype WheelEvent:DefaultPrevented·PreventDefault·StopPropagationtype Window:Buildtype WindowControl:Stringtype WindowHandle:UseWindow·Close·Focus·Hide·IsZero·Maximize·Minimize·Placement·SetFullscreen·Show·State·ToggleMaximize·Unmaximizetype WindowPlacementtype WindowState
Overview
Section titled “Overview”Package tela is the public API of Tela, a desktop UI framework written in pure Go: no cgo, no webview, a React-like component model and Tailwind CSS styling.
A UI is a tree of Node values built by components: struct values with a Build method (Component) and functions. Elements (Div, Button, Text…) live in the companion package h, designed to be dot-imported; this package holds the application (App, Main, Run), hooks and component boundaries (Component, UseState, C, CP…), events (MouseEvent, PointerEvent, DragEvent, KeyboardEvent with the KeyName and KeyCode constants, FocusEvent, and the ChangeEvent, InputEvent, CompositionEvent, SelectEvent and SubmitEvent of text fields and forms), ElementRef, the typed style props for h.Style, colors, and the Previews that tela snapshot and tela inspect render.
import ( "github.com/kuronosu/tela" . "github.com/kuronosu/tela/h")
func Counter() tela.Node { return tela.C(counter) }
func counter() tela.Node { count, setCount := tela.UseState(0) return Div(Class("flex flex-col items-center gap-6 p-10"), H1(Class("text-5xl font-bold"), Textf("Count: %d", count)), Button(Class("px-6 py-3 rounded-xl bg-indigo-500 text-white"), OnClick(func(tela.MouseEvent) { setCount.Set(count + 1) }), Text("Increment")), )}
func main() { tela.Main(tela.App{Title: "Demo", Width: 800, Height: 600, Root: Counter()})}Main runs the app and, if no window can be opened, prints the error and exits with status 1; Run returns the error instead.
Styling
Section titled “Styling”Static styling uses Tailwind v4 classes (h.Class). A class that depends on state goes in h.If, which takes props as well as nodes, and dynamic values go through typed props, which apply after the classes:
Div(Class("rounded-xl p-4"), If(selected, Class("ring-2 ring-indigo-500")), Style(tela.Width(w), tela.Bg(tela.Hex("#1e1e2e"))))h.Class takes several strings and joins them with a space, and a StyleProp is also a child, so Div(Class(“p-4”, tone), tela.Width(w)) needs neither concatenation nor Style; WH and Box set several at once.
Values that change every frame (a drag position, a progress bar) can be deferred to a later phase with TranslateFn, OpacityFn, WidthFn and HeightFn: a UseValue read inside them redoes only that element’s layout or paint when it changes (MapValue and h.Scale compute from one). Colors are extended sRGB; see Color.
Components
Section titled “Components”A component is a struct whose Build method returns a Node: its fields are its props, and children are an ordinary field of type Component (several of them through h.Fragment). Every component value given to an element is a component boundary: an element with its own hook state, rebuilt on its own when that state changes, and skipped when its parent builds again with an equal value and nothing it reads changed (automatic skipping, as in Jetpack Compose).
type Card struct { Title string OnOpen tela.Callback[func()] Children tela.Component}
func (c Card) Build() tela.Node { n, setN := tela.UseState(0) return Div(Class("rounded-xl border p-4"), H2(Text(c.Title)), Button(OnClick(func(tela.MouseEvent) { setN.Set(n + 1) }), Textf("Opened %d times", n)), c.Children)}
Div(Card{Title: "Inbox", Children: Fragment(Text("a"), Span(Text("b")))})Build has a value receiver. The identity of a component among its siblings is its type and its key (WithKey), and the comparison that skips its build never panics: see Component.
A function returning a Node is a component too when it is wrapped in C (no props) or CP (comparable props); CP skips like a struct component, and Memo does the same with a comparison function. Write the wrap where the component is defined, in a public function over a private one, so that nobody who uses it writes C or CP:
func Header() tela.Node { return tela.C(header) }
func Badge(p BadgeProps) tela.Node { return tela.CP(badge, p) }
Div(Header(), Badge(BadgeProps{Count: 3}))Calling Build, or a component function, directly runs it inside the caller, whose hook slots its hooks would take: in dev mode a hook called from a function that is neither the component being built (its Build, its function, or a function literal inside them) nor a custom hook panics with the fix. A custom hook is a function named UseXxx or useXxx that calls hooks for the component that calls it; a struct of Value pointers is a good thing for one to return, since it is stable and comparable:
type Drag struct{ X, Y *tela.Value[float32] }
func UseDrag() Drag { return Drag{X: tela.UseValue(float32(0)), Y: tela.UseValue(float32(0))}}A plain function without hooks (a wrapper that styles its children) needs no boundary; h.Fragment(children…) passes the children it receives through.
Hooks keep state and run code across builds, with React’s names and semantics:
UseState(andUseStateSet,UseStateUpdate) andUseReducerhold state; theirSetterandDispatcherare comparable, stable and safe from any goroutine.UseEffectruns code after the frame is presented andUseLayoutEffectafter layout, with cleanups, when their dependencies change;UseMountruns once, on mount (with its cleanup on unmount),UseEffectDohas no cleanup andUseUpdateEffectskips the first build.UseIntervalcalls a function every period on the UI thread,UseTimeoutonce after a delay, andUseGoruns a function on its own goroutine with a context that is cancelled when its dependencies change or the component unmounts.UseMemocaches a computation andUseOncecomputes a value once;UseCallbackgives a stableCallbackthat always calls the latest function;UseRefkeeps a mutable box.CreateContextandUseContextpass values down the tree.UseIDgives a stable unique ID.UseElementRefgives anElementRefto attach with h.Ref, to focus or scroll an element from handlers and effects.UseValueholds an observableValuefor what changes every frame: read in the component’s body, a change builds it again; read inside a deferred style closure, a change only lays out or repaints that element.UseScrollgives Values that follow an element’s scroll offsets, for effects tied to scrolling that repaint without rebuilding.UseBoundsgives a Value of an element’s bounds in the window (aRect, moved by scrolling and transforms), a ResizeObserver that also sees position; in a handler,ElementRef.Bounds reads them.
Scrolling
Section titled “Scrolling”An element with overflow-auto or overflow-scroll (per axis: overflow-x-*, overflow-y-*) scrolls with the wheel, the touchpad (with a kinetic fling when the fingers lift), touch, the keyboard (arrows, Page Up/Down, Home/End, Space) and its scrollbars; overflow-hidden scrolls only from code. The window itself scrolls like a browser page when the content is taller or wider than it (App.RootClass “overflow-hidden” turns that off); h-screen and h-full on the outer element still mean the window’s height. Wheel scrolling chains to the scrolling ancestors at an edge unless overscroll-contain stops it. Scrollbars are thin overlay bars that appear while scrolling; App.ClassicScrollbars (or the class scrollbar-classic) draws always-visible classic bars that take space. User scrolling animates; App.InstantScroll (or scroll-instant on an element) turns animation and flings off, scroll-smooth turns them back on, and the system’s reduced-motion setting always does. Code scrolls with ElementRef’s ScrollTo, ScrollBy and ScrollIntoView (animated with scroll-smooth, like CSS), and h.OnScroll and h.OnWheel observe it:
list := tela.UseElementRef()_, y := tela.UseScroll(list)header := Div(Class("h-16 bg-white shadow"), Style(tela.OpacityFn(func() float32 { return 1 - min(y.Get()/200, 1) // repaints only})))return Div(Class("flex h-screen flex-col"), header, Div(Ref(list), Class("grow overflow-y-auto"), rows), Button(OnClick(func(tela.MouseEvent) { list.ScrollTo(0, 0) }), Text("Top")))Long lists use h.VirtualList, which builds only the rows in view, keeps the scroll position stable while rows of unknown height are measured, and scrolls to a row with ElementRef’s ScrollToIndex and a ScrollAlign.
Text can be deferred the same way with h.TextFn: a Value read inside it lays out only the paragraph that holds the text, without building the component (a clock, a time label next to a seek bar).
A Value moved from a handler or a goroutine repaints only the element whose closure reads it:
pos := tela.UseValue(float32(0)) // UseValue(0.0) would hold a float64Div(Class("size-8 rounded-full bg-indigo-500"), Style(tela.TranslateFn(func() (x, y float32) { return pos.Get(), 0 })))// later, from anywhere: pos.Set(120)Hooks follow React’s rules: call them at the top level of a component’s Build or function, in the same order on every build, never inside conditions or loops. A hook called outside a component build panics with an explanation (a component called where a node is expected is told to use C, or to pass the struct value); in dev mode a change of the hook order panics with both call sites. Everything runs on the UI thread except the Setter, Dispatcher and Value methods and Post, which are safe from any goroutine.
Dev mode
Section titled “Dev mode”Dev mode reports the mistakes that compile. It is on unless the program is a release build (built with -trimpath, or installed with go install pkg@version; go run and go build in a source checkout are development builds); App.Dev overrides that, and TELA_DEV=1 or TELA_DEV=0 overrides both. telatest runs in dev mode unless telatest.NoDev says otherwise. In dev mode:
- unknown classes are printed on standard error with the closest class (in telatest they fail the test);
- unknown roles, input types and easings, hook-order changes, hooks called outside their component, a pointer given as a
Component, aPropin a field of type Component and a nil dependency list (UseEffect(f, nil): useOnceorUseMount) panic with the fix; - likely mistakes are printed as warnings, once per call site: lists without keys or with duplicate keys, dependencies that cannot be compared, a
Valueread with Get in a handler while changes are queued (use Latest), a context read without a Provider whose default is not safe to use, and an h.Label that labels no field.
Text fields and forms
Section titled “Text fields and forms”h.Input and h.Textarea are editable text fields with the editing, selection, clipboard, undo and IME behavior of a browser’s; h.Form submits on Enter or a submit button (h.OnSubmit), and h.Label names and focuses its field. Their events are ChangeEvent (every edit, React’s onChange), InputEvent (before an edit, cancelable), CompositionEvent, SelectEvent and SubmitEvent; ElementRef reads and selects their text (Value, Select, SetSelectionRange, SelectionRange). See fields.go for an example.
Snapshots and inspection
Section titled “Snapshots and inspection”A package that defines func Preview() tela.Node (or tela.Component), or a Previews variable of Preview values, can be rendered headlessly with tela snapshot, and tela inspect prints its semantics tree as a Playwright aria snapshot (roles, names and states set by the h.Role and h.Aria… props or implied by the elements) or, with –layout, its layout tree. A package-level var App = tela.App{...} gives both the window’s size, root class, color scheme, theme and class aliases, so the image matches the window; telatest.MountApp mounts the same App in a test. See the documentation of cmd/tela.
Stability
Section titled “Stability”Node, Component, Child, Prop, StyleProp, Color, Shadow, Gradient, GradientStop, Setter, Dispatcher, Callback, Ref, Context, Value, ElementRef, Rect, ScrollAlign, MouseEvent, PointerEvent, DragEvent, KeyboardEvent, FocusEvent, WheelEvent, ScrollEvent, InputEvent, ChangeEvent, CompositionEvent, SelectEvent, SubmitEvent, KeyName, KeyCode, KeyLocation, MouseButton, MouseButtons and PointerKind are aliases of types defined in Tela’s internal packages (the packages cannot be imported, but their exported fields and methods are part of the API shown here). Construct them with the functions of this package rather than with composite literals where one exists.
Constants
Section titled “Constants”const ( // MouseButtonNone is no button, as in a move or enter event. MouseButtonNone = core.MouseButtonNone // MouseButtonLeft is the primary button: the left button (the right // one on a left-handed setup), a touch contact or a pen tip. MouseButtonLeft = core.MouseButtonLeft // MouseButtonRight is the secondary button. MouseButtonRight = core.MouseButtonRight // MouseButtonMiddle is the wheel button. MouseButtonMiddle = core.MouseButtonMiddle // MouseButtonBack is the "back" side button. MouseButtonBack = core.MouseButtonBack // MouseButtonForward is the "forward" side button. MouseButtonForward = core.MouseButtonForward)The mouse buttons.
const ( PointerMouse = core.PointerMouse // a mouse or touchpad cursor PointerTouch = core.PointerTouch // a finger on a touchscreen PointerPen = core.PointerPen // a stylus)The pointer kinds.
const ( // KeyLocationStandard is every key not listed below. KeyLocationStandard = core.KeyLocationStandard // KeyLocationLeft is the left Shift, Control, Alt or Meta key. KeyLocationLeft = core.KeyLocationLeft // KeyLocationRight is the right Shift, Control, Alt (AltGr) or Meta key. KeyLocationRight = core.KeyLocationRight // KeyLocationNumpad is a key of the numeric keypad. KeyLocationNumpad = core.KeyLocationNumpad)The key locations (the DOM’s KeyboardEvent.location).
const ( // AlignAuto scrolls as little as possible: not at all when the item // is fully visible, else to align its bottom (when it reaches past // the bottom of the viewport) or its top. AlignAuto = core.AlignAuto // AlignStart puts the item's top at the top of the viewport. AlignStart = core.AlignStart // AlignCenter centers the item in the viewport. AlignCenter = core.AlignCenter // AlignEnd puts the item's bottom at the bottom of the viewport. AlignEnd = core.AlignEnd)The alignments of ElementRef.ScrollToIndex. The first and last items include the list’s padding: AlignStart on item 0 scrolls to the very top, AlignEnd on the last item to the very bottom.
const ( // WindowMinimize minimizes the window. WindowMinimize = core.WindowMinimize // WindowMaximize maximizes the window, or restores it when it is // maximized. WindowMaximize = core.WindowMaximize // WindowClose asks to close the window, as its close button does. WindowClose = core.WindowClose)const ( // BackdropDefault leaves the choice to the system: no material for a // plain window. BackdropDefault = core.BackdropDefault // BackdropNone turns the system material off. BackdropNone = core.BackdropNone // BackdropMica is Mica, the opaque material tinted with the desktop // wallpaper, for the main windows of an app. BackdropMica = core.BackdropMica // BackdropMicaAlt is Mica Alt, a stronger tint, for windows with tabs // in their title bar. BackdropMicaAlt = core.BackdropMicaAlt // BackdropAcrylic is Acrylic, the translucent blurred material of // transient surfaces such as flyouts. BackdropAcrylic = core.BackdropAcrylic)Variables
Section titled “Variables”var ( // Transparent is fully transparent black. Transparent = gfx.Transparent // Black is opaque black. Black = gfx.Black // White is opaque white. White = gfx.White)Common colors.
var Once = core.OnceOnce is the dependency of a hook that runs or computes only on the first build (React’s empty dependency list []):
tela.UseEffect(f, tela.Once) // after the first build; cleanup on unmounttela.UseLayoutEffect(f, tela.Once) // the same, before the first painttela.UseGo(f, tela.Once) // one goroutine for the component's lifetimetela.UseMemo(f, tela.Once) // computed onceIts type is unexported, so it is equal to itself on every build and is never confused with a value of yours. UseMount and UseOnce are the shorthands for effects and values. It replaces a single nil dependency (UseEffect(f, nil)): React reads a null list as “after every render”, so dev mode panics with this fix, and outside dev mode nil keeps meaning “only on mount”. With UseUpdateEffect, which skips the first build, Once never runs (dev mode warns).
Functions
Section titled “Functions”func Animate
Section titled “func Animate”func Animate[T Animatable](v *Value[T], target T, opts ...AnimationOption)Animate moves v to target: with a spring by default (Motion’s default, or as Stiffness, Damping, Bounce or Spring say), or with a tween when the options are Duration and Ease only. v is any Value of an Animatable type, from UseValue, UseSpring or UseTween.
y := tela.UseValue[float32](0)Button(OnClick(func(tela.MouseEvent) { tela.Animate(y, 200, tela.Spring(tela.Bounce(0.25))) }), Text("Drop"))tela.Animate(y, 0, tela.Duration(300*time.Millisecond), tela.Ease("ease-in-out"))A new Animate on the same Value interrupts the running animation: the new one starts where the value is and, for a spring, at the speed it has, so a fling continues smoothly; a Set or Update of the Value stops the animation. Like Set, Animate is safe from any goroutine: the animation starts when the UI thread applies it, in order with the Value’s Set and Update calls (an animation applied between two frames starts at the next one). Value.Latest does not anticipate animations: it returns the value they have reached.
With reduced motion, or in a tree that no frame clock drives, the value jumps to target. An animation of a Value whose component unmounts ends.
Example
t := &exampleT{}defer t.close()var y *tela.Value[float32]ball := func() tela.Node { y = tela.UseValue[float32](0) return Div( Button(OnClick(func(tela.MouseEvent) { tela.Animate(y, 200, tela.Spring(tela.Bounce(0.25))) }), Text("Drop")), Button(OnClick(func(tela.MouseEvent) { tela.Animate(y, 0, tela.Duration(300*time.Millisecond), tela.Ease("ease-in-out")) }), Text("Lift")), Div(Class("size-8 rounded-full bg-indigo-500"), Style(tela.TranslateFn(func() (float32, float32) { return 0, y.Get() }))))}app := telatest.Mount(t, tela.C(ball))app.Click(telatest.ByRole("button", "Drop")) // settles: the spring endsfmt.Println(y.Get())app.Click(telatest.ByRole("button", "Lift"))fmt.Println(y.Get())// Output:// 200// 0func Assets
Section titled “func Assets”func Assets(fsys fs.FS)Assets registers a file system that images are loaded from: the path in a class such as bg-[url(img/hero.jpg)] or mask-[url(icons/star.svg)], or in h.SrcPath(“img/logo.svg”), names a file of fsys, relative to its root (a leading “/” or “./” is ignored, so url(/img/hero.jpg) is the same file; “..” is not allowed). Call it from an init function, so that the files are found the same way by Run, tela snapshot, tela inspect and telatest:
//go:embed imgvar images embed.FS
func init() { tela.Assets(images) }Assets may be called several times: the file systems are searched in the order they were registered and the first one that has the file wins. Files are decoded once, when first used, and kept for the life of the process: PNG, JPEG, GIF (the first frame), WebP and SVG (drawn as vectors), recognized by their content. A missing or undecodable file paints nothing and is reported once in the dev log, with the path and the registered file systems, like an unknown class. Remote and data: URLs are not supported.
Example
// An app embeds its images and registers them from an init function://// //go:embed img// var images embed.FS//// func init() { tela.Assets(images) }//// Here an in-memory file system holds one red PNG.tela.Assets(fstest.MapFS{"img/red.png": {Data: solidPNG(color.RGBA{R: 255, A: 255})}})
// With package h: Div(Class("size-8 bg-[url(img/red.png)] bg-cover")).card := core.Primitive(style.KindDiv, core.Class("size-8 bg-[url(img/red.png)] bg-cover"))_, img := core.Render(card, core.RenderOptions{Width: 32, Height: 32})fmt.Println(img.RGBAAt(16, 16))// Output: {255 0 0 255}func DevMode
Section titled “func DevMode”func DevMode() boolDevMode reports whether dev mode is on where it is called: in a build, the mode of the tree being built (App.Dev, telatest.NoDev); elsewhere the process default, on unless the program is a release build, with TELA_DEV=1 or TELA_DEV=0 overriding both (ADR-085, ADR-093). Component libraries use it to check their own props the way Tela checks classes and roles: panic with the fix in dev mode, fall back quietly otherwise. It is a lookup and costs nothing.
func Main
Section titled “func Main”func Main(app App)Main runs app with Run and, when Run returns an error (no display, for example), prints it on standard error and exits with status 1. It is the usual body of main:
func main() { tela.Main(tela.App{Title: "Demo", Width: 800, Height: 600, Root: Counter()})}where Counter is a function that returns tela.C(counter). Main returns when the window is closed. Like Run, it must be called from the main goroutine, and it panics when app.Root is nil.
Example
counter := func() tela.Node { count, setCount := tela.UseState(0) return Button(OnClick(func(tela.MouseEvent) { setCount.Set(count + 1) }), Textf("Clicked %d times", count))}// In package main. Main returns when the window is closed; without a// display it prints the error and exits with status 1.tela.Main(tela.App{Title: "Demo", Width: 400, Height: 300, Root: tela.C(counter)})func MapValue
Section titled “func MapValue”func MapValue[T, U any](v *Value[T], f func(T) U) func() UMapValue returns a function that reads v and applies f, for the deferred style props (WidthFn, HeightFn, OpacityFn, BgFn, TextColorFn), which take a func with one result: v is read, and tracked, when the prop is evaluated in a later phase, not when the component builds.
Style(tela.HeightFn(tela.MapValue(open, func(t float32) float32 { return 36 + 120*t })))Style(tela.BgFn(tela.MapValue(progress, func(p float32) tela.Color { return mix(from, to, p) })))h.Scale is MapValue for a float32 times a constant.
Example
t := &exampleT{}defer t.close()var open *tela.Value[float32]panel := func() tela.Node { open = tela.UseValue(float32(0)) // 36 px closed, 156 px open: only the box is laid out again when // open changes, the component does not build. return Div(TestID("panel"), Class("w-40 overflow-hidden bg-slate-100"), Style(tela.HeightFn(tela.MapValue(open, func(t float32) float32 { return 36 + 120*t }))))}app := telatest.Mount(t, tela.C(panel))fmt.Println(app.Bounds(telatest.ByTestID("panel")).Height)tela.Animate(open, 1, tela.Duration(100*time.Millisecond))app.Advance(time.Second)fmt.Println(app.Bounds(telatest.ByTestID("panel")).Height)// Output:// 36// 156func OpenPath
Section titled “func OpenPath”func OpenPath(path string) errorOpenPath opens a local file in its default application, or a folder in the file manager. Call it on the UI thread (a handler, an effect); from another goroutine, wrap it in Post.
func OpenURL
Section titled “func OpenURL”func OpenURL(url string) errorOpenURL opens url in the user’s default application for its scheme: a web page in the browser, a mailto: address in the mail client. The URL must have a scheme (“https://example.com”); open local files and folders with OpenPath. The error reports a URL that cannot be opened or a desktop without the service (headless). Call it on the UI thread (a handler, an effect); from another goroutine, wrap it in Post.
func Post
Section titled “func Post”func Post(fn func())Post runs fn on the UI thread of the running application, in order with the state updates queued before and after it. It is safe from any goroutine; use it to touch UI-thread state (a Ref, a Callback’s forwarder) from background work.
go func() { data := fetch() tela.Post(func() { cache.Current = data })}()Functions posted before Run starts run once its window is up. Headless trees (tests, snapshots) do not run posted functions unless they receive them (telatest.Mount does); until then they wait, in order.
func Quit
Section titled “func Quit”func Quit()Quit quits the app: Run returns (and Main with it) after unmounting every window, which runs the cleanups of their effects. It is safe from any goroutine and is applied in order with the state updates queued before it.
func Run
Section titled “func Run”func Run(app App) errorRun opens a window, shows app.Root and runs the event loop until the app quits: the main window is closed (unless App.OnClose says otherwise) or Quit is called. The windows unmount before Run returns, running the cleanups of their effects. It must be called from the main goroutine, normally from main. The window is drawn by Tela’s own renderer on the native backend: Wayland or X11 on Linux, Win32 and Cocoa elsewhere; Window components open more windows.
Run returns an error when the platform cannot open a window (for example, no display is available). It panics when app.Root is nil. Main runs it and handles the error.
func SetColorScheme
Section titled “func SetColorScheme”func SetColorScheme(s ColorScheme)SetColorScheme sets the color scheme of the running app: Light or Dark override the system’s preference, System follows it again. Every element is styled again (dark: classes) and the components that call UseColorScheme build again. It is safe from any goroutine, like a state setter: the change applies on the UI thread before the next frame. Called before Run, it applies when the window opens (it wins over App.ColorScheme). Like Post, it goes to the app that receives posted functions (telatest.Mount’s app in tests).
Button(OnClick(func(tela.MouseEvent) { tela.SetColorScheme(tela.Dark) }), Text("Dark"))It panics for a value other than System, Light and Dark.
Example
toggle := func() tela.Node { dark := tela.UseColorScheme() == tela.Dark next, label := tela.Dark, "Dark mode" if dark { next, label = tela.Light, "Light mode" } return Button(Class("bg-white text-black dark:bg-black dark:text-white"), OnClick(func(tela.MouseEvent) { tela.SetColorScheme(next) }), Text(label))}app := telatest.Mount(t, tela.C(toggle))defer app.Close()app.Click(telatest.ByRole("button", "Dark mode"))fmt.Println(app.AriaSnapshot())// Output:// - button "Light mode"func SetTheme
Section titled “func SetTheme”func SetTheme(t Theme)SetTheme replaces the theme of the running app: classes are compiled again against it (with the app’s ClassAliases), every element is styled again and the components that call UseTheme build again. Like SetColorScheme it is safe from any goroutine, applies on the UI thread before the next frame, goes to the app that receives posted functions, and called before Run applies when the window opens (it wins over App.Theme). It panics for a token name classes cannot use.
func Toggle
Section titled “func Toggle”func Toggle(set Setter[bool]) func()Toggle returns a function that flips set’s state, for a handler: OnClick(tela.Toggle(setOpen)). It uses Setter.Update, so two clicks that land in one frame both count and the state ends where it started, which setOpen.Set(!open) does not give (both clicks read the same open).
open, setOpen := tela.UseState(false)Button(OnClick(tela.Toggle(setOpen)), Text("Menu"))Example
t := &exampleT{}defer t.close()menu := func() tela.Node { open, setOpen := tela.UseState(false) return Div( Button(OnClick(tela.Toggle(setOpen)), Text("Menu")), If(open, P(Text("Settings"))))}app := telatest.Mount(t, tela.C(menu))app.Click(telatest.ByRole("button", "Menu"))fmt.Println(app.Count(telatest.ByText("Settings")))app.Click(telatest.ByRole("button", "Menu"))fmt.Println(app.Count(telatest.ByText("Settings")))// Output:// 1// 0func UseContext
Section titled “func UseContext”func UseContext[T any](ctx *Context[T]) TUseContext returns the value of the nearest Provider of ctx above the component, or the context’s default when there is none.
theme := tela.UseContext(Theme)In dev mode, reading a context without a Provider above warns (once per context) when its default is not safe to use: nil, or holding a nil function, pointer, map, channel or interface, or a zero Setter or Callback, in an exported field. Either provide the context above every reader, or give CreateContext a default that works; IsZero tells a zero Setter or Callback apart where a missing Provider is expected.
func UseDirection
Section titled “func UseDirection”func UseDirection() stringUseDirection returns the writing direction at the component’s position, “ltr” or “rtl”: the one the nearest element above it with an h.Dir prop gives, else “ltr”. Under h.Dir(“auto”) it is the direction that element resolves from its text; the first build of a component below an auto element that has not been styled yet reads “ltr”, and when the element resolves to “rtl” the component builds again before the frame is laid out, so the wrong direction never reaches the screen. Content of an h.Portal follows the position where the Portal is declared. The component builds again when the direction changes (a Dir prop above it, or the text of an auto element), like with a state hook; nothing else does. It is a hook: call it at the top level of a component.
Classes do not need it: the logical utilities (ms-*, ps-*, start-*, rounded-s-*…) and the rtl: and ltr: variants already follow the direction. Use it for what classes cannot do, such as the arrow keys or the drag of a slider:
func Stepper() tela.Node { next := "ArrowRight" if tela.UseDirection() == "rtl" { next = "ArrowLeft" } ...}It is a string, the vocabulary of h.Dir and of Radix’s useDirection, so the value passes as it is to h.Dir and to the Direction fields of kit and aria.
Example
arrow := func() tela.Node { next := "ArrowRight" if tela.UseDirection() == "rtl" { next = "ArrowLeft" } return h.P(h.Textf("Next: %s", next))}app := func() tela.Node { return h.Div(tela.C(arrow), h.Div(h.Dir("rtl"), tela.C(arrow)))}yaml, _ := telatest.AriaSnapshot(tela.C(app))fmt.Println(yaml)// Output:// - paragraph: "Next: ArrowRight"// - paragraph: "Next: ArrowLeft"func UseEffect
Section titled “func UseEffect”func UseEffect(effect func() func(), deps ...any)UseEffect runs effect after the frame is presented, when its dependencies changed since the previous build. effect may return a cleanup function (or nil), which runs before the effect runs again and when the component unmounts.
The dependencies follow React:
tela.UseEffect(f) // after every buildtela.UseEffect(f, id, n) // when id or n changed (compared with ==)tela.UseEffect(f, tela.Once) // only after the first build (React's [])tela.UseMount(f) // the sameFor an effect that runs once, on mount, with its cleanup on unmount (a subscription), use UseMount or Once; UseEffectDo takes an effect without a cleanup, UseUpdateEffect skips the first build, and periodic and background work have UseInterval and UseGo. A single nil dependency, UseEffect(f, nil), is rejected in dev mode with the fix (Once: React reads a null list as “after every render”); outside dev mode it keeps meaning “only on mount”.
Values that cannot be compared (functions, slices, maps) count as changed on every build; dev mode reports them, and a dependency count that changes between builds. Pass an ID, a comparable value or a Callback instead.
Within a frame, the effects of children run before their parents’, and every cleanup runs before the effects that follow it. Effects of a component whose build was skipped do not run. State set by an effect is applied in a later frame.
func UseEffectDo
Section titled “func UseEffectDo”func UseEffectDo(f func(), deps ...any)UseEffectDo is UseEffect for an effect without a cleanup: f runs after the frame is presented when the dependencies changed.
tela.UseEffectDo(func() { title.Set(fmt.Sprintf("%d unread", n)) }, n)Example
t := &exampleT{}defer t.close()var title stringinbox := func() tela.Node { unread, setUnread := tela.UseState(3) tela.UseEffectDo(func() { title = fmt.Sprintf("Inbox (%d)", unread) }, unread) return Button(OnClick(func(tela.MouseEvent) { setUnread.Set(0) }), Text("Mark all read"))}app := telatest.Mount(t, tela.C(inbox))fmt.Println(title)app.Click(telatest.ByRole("button", "Mark all read"))fmt.Println(title)// Output:// Inbox (3)// Inbox (0)func UseGo
Section titled “func UseGo”func UseGo(f func(ctx context.Context), deps ...any)UseGo runs f on a goroutine of its own after the frame is presented, when its dependencies changed, like UseEffect; ctx is cancelled at cleanup, when the dependencies change again or the component unmounts, before the next run starts. f must return soon after ctx is done (it is not waited for) and must change the UI only through what is safe from any goroutine: a Setter, a Value, Post.
tela.UseGo(func(ctx context.Context) { for page := range fetchPages(ctx, query) { setResults.Update(func(r []Result) []Result { return append(r, page...) }) }}, query) // restarts, cancelling the old fetch, when query changesThe dependencies follow UseEffect’s: none restarts f after every build, and Once runs one goroutine for the lifetime of the component.
Example
t := &exampleT{}defer t.close()search := func(ctx context.Context, q string) []string { return []string{q + " one", q + " two"} // a slow call that honors ctx}results := func() tela.Node { query, setQuery := tela.UseState("tela") found, setFound := tela.UseState([]string(nil)) tela.UseGo(func(ctx context.Context) { r := search(ctx, query) if ctx.Err() == nil { // a newer query cancelled this one setFound.Set(r) // safe from any goroutine } }, query) return Div( Button(OnClick(func(tela.MouseEvent) { setQuery.Set("go") }), Text("Search go")), Map(found, func(s string) tela.Node { return P(Key(s), Text(s)) }), )}app := telatest.Mount(t, tela.C(results))app.ExpectText("tela two") // expectations wait for the goroutineapp.Click(telatest.ByRole("button", "Search go"))app.ExpectText("go one")fmt.Println("ok")// Output: okfunc UseID
Section titled “func UseID”func UseID() stringUseID returns a string that identifies this hook slot, for accessibility relations between elements (a label and its input). It is the same on every build, unique within the process, and the same for the same mount order (snapshots are deterministic).
id := tela.UseID()return Div(Label(For(id), Text("Email")), Input(ID(id)))func UseInterval
Section titled “func UseInterval”func UseInterval(d time.Duration, f func())UseInterval calls f on the UI thread every d, the first time d after the frame that first shows the component, until it unmounts. d <= 0 pauses it, and a new d restarts it. f is always the latest build’s function, so it sees the latest state and needs no dependencies. It runs on the window’s frame clock, like the long-press timer, with no goroutine: telatest’s App.Advance moves it, and a headless Render never runs it.
now, setNow := tela.UseState(time.Now())tela.UseInterval(time.Second, func() { setNow.Set(time.Now()) })Example
t := &exampleT{}defer t.close()timer := func() tela.Node { seconds, setSeconds := tela.UseState(0) running, setRunning := tela.UseState(true) period := time.Second if !running { period = 0 // paused } tela.UseInterval(period, func() { setSeconds.Set(seconds + 1) }) return Div( P(Textf("%d s", seconds)), Button(OnClick(func(tela.MouseEvent) { setRunning.Set(!running) }), Text("Pause")), )}app := telatest.Mount(t, tela.C(timer))app.Advance(3 * time.Second) // the interval runs on the app's clockapp.ExpectText("3 s")app.Click(telatest.ByRole("button", "Pause"))app.Advance(5 * time.Second)app.ExpectText("3 s")fmt.Println("ok")// Output: okfunc UseLayoutEffect
Section titled “func UseLayoutEffect”func UseLayoutEffect(effect func() func(), deps ...any)UseLayoutEffect is UseEffect, but the effect runs in the frame after layout and before paint, with the same dependencies and cleanups. Its state updates are applied in the next frame. The scrolls it asks for (ElementRef’s ScrollTo, ScrollBy, ScrollIntoView and ScrollToIndex) use the layout of its frame, which is painted scrolled: on mount, and when the content just grew.
last := tela.UseElementRef() // on the newest messagetela.UseLayoutEffect(func() func() { last.ScrollIntoView() // the frame that shows a new message shows it in view return nil}, len(messages))func UseMemo
Section titled “func UseMemo”func UseMemo[T any](compute func() T, deps ...any) TUseMemo returns compute(), computed on the first build and again only when the dependencies changed (compared like UseEffect’s: none recomputes on every build). For a value computed once, use UseOnce (or UseMemo(compute, tela.Once)).
visible := tela.UseMemo(func() []Todo { return filter(todos, query) }, len(todos), query)func UseMount
Section titled “func UseMount”func UseMount(effect func() func())UseMount runs effect once, after the frame that first shows the component, and the cleanup it returns (nil for none) when the component unmounts: the idiom for subscriptions, listeners and other setup that lives as long as the component (React’s useEffect(f, [])).
tela.UseMount(func() func() { unsubscribe := store.Subscribe(func(s State) { setState.Set(s) }) return unsubscribe})Example
t := &exampleT{}defer t.close()var events []stringpanel := func() tela.Node { tela.UseMount(func() func() { events = append(events, "subscribe") return func() { events = append(events, "unsubscribe") } }) return Text("Panel")}page := func() tela.Node { open, setOpen := tela.UseState(true) return Div( Button(OnClick(func(tela.MouseEvent) { setOpen.Set(!open) }), Text("Toggle")), If(open, tela.C(panel)), )}app := telatest.Mount(t, tela.C(page))app.Click(telatest.ByRole("button", "Toggle")) // unmounts the panelapp.Click(telatest.ByRole("button", "Toggle")) // mounts it againfmt.Println(events)// Output: [subscribe unsubscribe subscribe]func UseOnce
Section titled “func UseOnce”func UseOnce[T any](init func() T) TUseOnce returns init(), called on the first build only; later builds return the same value. Use it for what a component creates once and keeps: a client, a buffer, the state struct of a custom hook. It is UseMemo without dependencies; the value is not reactive (store what changes in UseState or UseValue).
cache := tela.UseOnce(func() map[string]Image { return map[string]Image{} })Example
t := &exampleT{}defer t.close()created := 0type cache struct{ hits map[string]int }page := func() tela.Node { c := tela.UseOnce(func() *cache { created++; return &cache{hits: map[string]int{}} }) n, setN := tela.UseState(0) c.hits["build"]++ return Button(OnClick(func(tela.MouseEvent) { setN.Set(n + 1) }), Textf("Add %d", n))}app := telatest.Mount(t, tela.C(page))app.Click(telatest.ByText("Add"))app.Click(telatest.ByText("Add"))fmt.Println("created", created, "times")// Output: created 1 timesfunc UsePresence
Section titled “func UsePresence”func UsePresence() (present bool, done func())UsePresence reports whether the component is present, for a component inside a child of an h.Presence: present is false while that child exits, after it was removed. The component then runs its own exit (an Animate, saving a draft…) and calls done when it is finished; the child unmounts once every component that used UsePresence called done and the transitions of its h.Exit classes ended. done is the same function on every build, safe from any goroutine, and does nothing while the component is present (a call from a previous exit that was cancelled is ignored). Outside any Presence, present is always true.
A toast that slides down and fades out before it unmounts: the tween to its exit position calls done when it arrives (OnDone; done does nothing while the toast is present, so the entrance may pass it too).
func Toast(msg string) tela.Node { present, done := tela.UsePresence() target := float32(0) if !present { target = 1 } out := tela.UseTween(target, tela.Duration(200*time.Millisecond), tela.OnDone(done)) return Div(Class("rounded-lg bg-slate-900 px-4 py-2 text-white"), Style(tela.TranslateFn(func() (float32, float32) { return 0, 40 * out.Get() }), tela.OpacityFn(func() float32 { return 1 - out.Get() })), Text(msg))}
Presence(If(saved, tela.C(func() tela.Node { return Toast("Saved") })))Example
t := &exampleT{}defer t.close()toast := func() tela.Node { present, done := tela.UsePresence() target := float32(0) if !present { target = 1 } // The tween out ends the exit: done does nothing while present. out := tela.UseTween(target, tela.Duration(200*time.Millisecond), tela.OnDone(done)) return Div(Role("status"), Class("rounded-lg bg-slate-900 px-4 py-2 text-white"), Style(tela.OpacityFn(func() float32 { return 1 - out.Get() })), Text("Saved"))}page := func() tela.Node { shown, setShown := tela.UseState(true) return Div( Button(OnClick(func(tela.MouseEvent) { setShown.Set(false) }), Text("Dismiss")), Presence(If(shown, tela.C(toast))))}app := telatest.Mount(t, tela.C(page))start := app.Now()app.Click(telatest.ByRole("button", "Dismiss")) // waits for the exitfmt.Println(app.Count(telatest.ByRole("status", "")), app.Now()-start >= 200*time.Millisecond)// Output: 0 truefunc UseReducedMotion
Section titled “func UseReducedMotion”func UseReducedMotion() boolUseReducedMotion reports whether the system asks for reduced motion (the motion-reduce: classes apply, transitions take no time and scrolling jumps). The component builds again when it changes. It is a hook: call it at the top level of a component.
Example
spinner := func() tela.Node { if tela.UseReducedMotion() { return P(Text("Loading…")) } return Div(Class("size-6 animate-spin rounded-full border-2 border-t-transparent"), AriaLabel("Loading"), Role("status"))}yaml, _ := telatest.AriaSnapshot(tela.C(spinner), telatest.ReducedMotion())fmt.Println(yaml)// Output:// - paragraph: Loading…func UseStateSet
Section titled “func UseStateSet”func UseStateSet[T any](initial T) (T, func(T))UseStateSet is UseState for those who only set whole values: it returns the Setter’s Set method as a plain function, made once per slot.
name, setName := tela.UseStateSet("")setName("Ada")It exists for code that wants React’s shape, a setter that is a function: to pass it where a func(T) is expected (a callback of a library, a field’s handler) without wrapping it, and to keep code ported from React reading the same. The function is the same on every build, but funcs are not comparable in Go, so a props struct holding one makes CP rebuild its component every time; pass the Setter of UseState in props instead.
func UseStateUpdate
Section titled “func UseStateUpdate”func UseStateUpdate[T any](initial T) (T, func(func(T) T))UseStateUpdate is UseState for those who only update from the previous state: it returns the Setter’s Update method as a plain function, made once per slot, for the same reasons as UseStateSet.
count, update := tela.UseStateUpdate(0)update(func(n int) int { return n + 1 })func UseTimeout
Section titled “func UseTimeout”func UseTimeout(d time.Duration, f func(), deps ...any)UseTimeout calls f once on the UI thread, d after the frame that first shows the component: the one-shot sibling of UseInterval, on the same frame clock with no goroutine (telatest’s App.Advance moves it, and a headless Render never runs it). An idle timeout costs one timer, and none once it has fired.
d <= 0 cancels it. A change of d or of the dependencies (compared like UseEffect’s) restarts it from the frame that shows the change, even after it fired; with the same d and no dependencies it fires once per mount. f is always the latest build’s function, so it sees the latest state without being a dependency. Unmounting cancels it.
Hide a notice 3 s after it appears, restarting when the message changes:
tela.UseTimeout(3*time.Second, func() { setVisible.Set(false) }, message)Example
t := &exampleT{}defer t.close()banner := func() tela.Node { visible, setVisible := tela.UseState(true) // Hide the notice 3 s after it appears. tela.UseTimeout(3*time.Second, func() { setVisible.Set(false) }) return Div(If(visible, P(Text("Saved"))), P(Text("Done")))}app := telatest.Mount(t, tela.C(banner))app.Advance(2 * time.Second)fmt.Println(app.Count(telatest.ByText("Saved")))app.Advance(2 * time.Second) // the timeout runs on the app's clockfmt.Println(app.Count(telatest.ByText("Saved")))// Output:// 1// 0func UseUpdateEffect
Section titled “func UseUpdateEffect”func UseUpdateEffect(effect func() func(), deps ...any)UseUpdateEffect is UseEffect without the run of the first build: the effect runs after the later builds whose dependencies changed (react-use’s useUpdateEffect), and its cleanup before it runs again and on unmount. Use it to react to changes, not to the initial value.
tela.UseUpdateEffect(func() func() { save(settings) // not on mount, only when settings change return nil}, settings)Example
t := &exampleT{}defer t.close()var saved []stringeditor := func() tela.Node { theme, setTheme := tela.UseState("light") tela.UseUpdateEffect(func() func() { saved = append(saved, theme) // not on mount: only changes are saved return nil }, theme) return Button(OnClick(func(tela.MouseEvent) { setTheme.Set("dark") }), Text("Dark"))}app := telatest.Mount(t, tela.C(editor))fmt.Println(saved)app.Click(telatest.ByRole("button", "Dark"))fmt.Println(saved)// Output:// []// [dark]type Animatable
Section titled “type Animatable”type Animatable = core.AnimatableAnimatable lists the types that UseSpring, UseTween and Animate animate:
- float32: a number (an offset, a scale, an opacity, a progress);
Color: interpolated as CSS transitions interpolate colors, premultiplied by alpha, in sRGB between two colors written as hex, rgb() or named colors, and in Oklab otherwise (the Oklch palette of Tailwind,OKLCH); read it in aBgFnorTextColorFnto animate a color by repainting only;Point,SizeandRect: component by component, each with its own velocity.
Animatable is an alias of core.Animatable, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type Animatable interface { float32 | gfx.Color | Point | Size | Rect}Example
t := &exampleT{}defer t.close()var bg *tela.Value[tela.Color]app := telatest.Mount(t, tela.C(func() tela.Node { bg = tela.UseValue(tela.Hex("#ffffff")) // Read in the paint phase: the animation only repaints the box. return Div(Class("size-10"), Style(tela.BgFn(bg.Get)))}), telatest.NoSettle())// Hex colors interpolate in sRGB, like a CSS transition between them.tela.Animate(bg, tela.Hex("#000000"), tela.Duration(100*time.Millisecond), tela.Ease("linear"))app.Advance(50 * time.Millisecond) // 33 ms of the tween: see ExamplePointfmt.Println(bg.Get())// Output: #aaaaaatype AnimationOption
Section titled “type AnimationOption”type AnimationOption = core.AnimOptionAnimationOption configures an animation of UseSpring, UseTween or Animate: Stiffness, Damping, Bounce, Duration, Ease, Velocity and Spring, which groups spring options, OnDone, and Initial for the start value of UseSpring and UseTween. The zero AnimationOption changes nothing.
Springs (Motion’s model) are defined either by their physics or by how long they take:
tela.Stiffness(300), tela.Damping(30) // physics; mass 1tela.Spring(tela.Duration(500*time.Millisecond), tela.Bounce(0.25))Without options a spring has stiffness 100 and damping 10 (Motion’s default, slightly bouncy); Bounce without a Duration takes 800 ms, and a Duration without Bounce a bounce of 0.3. Tweens take a Duration (default 300 ms) and an Ease (default CSS’s “ease”).
Options that contradict each other or the hook (Ease on a spring, Stiffness and Duration together, spring options on UseTween), invalid numbers and invalid easing strings panic in dev mode (see App.Dev) with what to write instead; otherwise they are ignored.
AnimationOption is an alias of core.AnimOption, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type AnimOption struct { // contains filtered or unexported fields}Example
// Options for the three kinds of motion.physics := []tela.AnimationOption{tela.Stiffness(300), tela.Damping(30)}timed := []tela.AnimationOption{tela.Spring(tela.Duration(400*time.Millisecond), tela.Bounce(0.2))}tween := []tela.AnimationOption{tela.Duration(250 * time.Millisecond), tela.Ease("cubic-bezier(0, 0, 0.2, 1)")}fmt.Println(len(physics), len(timed), len(tween))// Output: 2 1 2func Bounce
Section titled “func Bounce”func Bounce(b float64) AnimationOptionBounce sets how bouncy a spring defined by its duration is (Motion’s bounce): 0 does not overshoot, 0.25 bounces a little, values toward 1 oscillate longer. Without a Duration the spring takes 800 ms. It makes Animate use a spring.
Example
// A spring defined by its duration (800 ms without Duration) ends no// earlier than it, at rest.fmt.Println("bounce 0:", springEnd(tela.Spring(tela.Bounce(0))))fmt.Println("bounce 0.5:", springEnd(tela.Spring(tela.Bounce(0.5))))// Output:// bounce 0: 830ms// bounce 0.5: 870msfunc Damping
Section titled “func Damping”func Damping(c float64) AnimationOptionDamping sets the damping of a spring: how strongly it resists motion (default 10). Low values bounce around the target; damping = 2*sqrt(stiffness) is critically damped (no overshoot), so Stiffness(300) with Damping(35) settles without bouncing. It makes Animate use a spring.
Example
// Damping 2*sqrt(stiffness) is critically damped: no overshoot. Less// bounces around the target and takes longer to come to rest.fmt.Println("damping 40:", springEnd(tela.Stiffness(400), tela.Damping(40)))fmt.Println("damping 10:", springEnd(tela.Stiffness(400), tela.Damping(10)))// Output:// damping 40: 480ms// damping 10: 1.15sfunc Duration
Section titled “func Duration”func Duration(d time.Duration) AnimationOptionDuration sets how long a tween takes, or, for a spring (UseSpring, or inside Spring), the time a spring found from it settles in (Motion’s duration/bounce springs; it ends no earlier). A Duration of 0 jumps to the target: the value is stored at once, a tween’s or a spring’s, and an OnDone is queued right after, as for any target that applies at once.
Example
fmt.Println("tween:", springEnd(tela.Duration(250*time.Millisecond)))fmt.Println("spring:", springEnd(tela.Spring(tela.Duration(250*time.Millisecond))))// Output:// tween: 270ms// spring: 320msfunc Ease
Section titled “func Ease”func Ease(e Easing) AnimationOptionEase sets the easing curve of a tween, an Easing: a CSS <easing-function>, one of the keywords linear, ease, ease-in, ease-out, ease-in-out, step-start and step-end, CubicBezier or steps(n[, position]). The keywords are CSS’s curves: Tailwind’s ease-out utility is Ease(CubicBezier(0, 0, 0.2, 1)). An invalid string panics in dev mode with a suggestion (Ease(“ease-out-cubic”): did you mean “ease-out”?); otherwise the tween uses “ease”.
Example
fmt.Println("ease-out:", springEnd(tela.Ease("ease-out"))) // 300 ms by defaultfmt.Println("steps:", springEnd(tela.Duration(time.Second), tela.Ease("steps(4, jump-end)")))// Output:// ease-out: 320ms// steps: 1.03sfunc Initial
Section titled “func Initial”func Initial[T Animatable](v T) AnimationOptionInitial sets the value UseSpring and UseTween hold on their first build, from which they move to their target: an entrance animation. Without it they start at the target, and nothing moves until the target changes. Later builds ignore it.
scale := tela.UseSpring(float32(1), tela.Initial(float32(0.8))) // pops inIts type must be the target’s. AnimationOption is not generic, so the compiler cannot check that: a mismatch, such as tela.UseSpring(tela.Point{}, tela.Initial(float32(0))), panics in dev mode (see App.Dev) and is ignored otherwise (the value starts at the target). It does not apply to Animate, which starts where the Value is (dev mode panics), nor inside Spring.
func OnDone
Section titled “func OnDone”func OnDone(fn func()) AnimationOptionOnDone calls fn when the animation comes to rest at its target: once, on the UI thread, queued with the state updates like Post, so it runs before the next build and state it sets is built in the frame that shows the target. It is not called when the animation is interrupted: by another Animate, Set or Update of the Value, by a new target of UseSpring or UseTween, or by the unmount of the Value’s component. When the target applies at once (reduced motion, a tree that no frame clock drives, Duration(0), a value already at its target and at rest, a NaN target) fn is queued right after it applies. For UseSpring and UseTween it is the OnDone of the build that set the target that runs.
tela.Animate(x, 0, tela.Spring(), tela.OnDone(func() { setOpen.Set(false) }))It is how a component inside an h.Presence child ends its own exit: see UsePresence.
Example
t := &exampleT{}defer t.close()var x *tela.Value[float32]var log []stringapp := telatest.Mount(t, tela.C(func() tela.Node { x = tela.UseValue[float32](0) return Div(Class("size-8 bg-black"), Style(tela.TranslateFn(func() (float32, float32) { return x.Get(), 0 })))}), telatest.NoSettle())tela.Animate(x, 100, tela.OnDone(func() { log = append(log, "first") }))app.Advance(50 * time.Millisecond)// Interrupted: the first OnDone never runs.tela.Animate(x, 0, tela.Duration(100*time.Millisecond), tela.OnDone(func() { log = append(log, "second") }))app.Advance(time.Second)fmt.Println(log, x.Get())// Output: [second] 0func Spring
Section titled “func Spring”func Spring(opts ...AnimationOption) AnimationOptionSpring makes the animation a spring with the options given: Stiffness and Damping, or Duration and Bounce. Spring() alone is Motion’s default spring. It is how Animate gets a spring defined by its duration:
tela.Animate(y, 200, tela.Spring(tela.Duration(400*time.Millisecond), tela.Bounce(0.3)))Example
fmt.Println("Motion's default:", springEnd(tela.Spring()))fmt.Println("500 ms, bounce 0.3:", springEnd(tela.Spring(tela.Duration(500*time.Millisecond), tela.Bounce(0.3))))// Output:// 500 ms, bounce 0.3: 530msfunc Stiffness
Section titled “func Stiffness”func Stiffness(k float64) AnimationOptionStiffness sets the stiffness of a spring: how strongly it pulls the value to its target (default 100). Higher is faster. With Damping it defines the spring by its physics, so it cannot be combined with Duration or Bounce. It makes Animate use a spring.
Example
// Four times the stiffness (with the damping that keeps both critically// damped) arrives in about half the time.fmt.Println("stiffness 100:", springEnd(tela.Stiffness(100), tela.Damping(20)))fmt.Println("stiffness 400:", springEnd(tela.Stiffness(400), tela.Damping(40)))// Output:// stiffness 100: 870ms// stiffness 400: 480msfunc Velocity
Section titled “func Velocity”func Velocity[T Animatable](v T) AnimationOptionVelocity sets the initial velocity of a spring, in the Value’s units per second, component by component (a Point’s X and Y, a Rect’s X, Y, Width and Height). It replaces the velocity an interrupted animation would pass on: a released drag hands its pointer velocity to the spring that brings the element back:
OnDragEnd(func(e tela.DragEvent) { tela.Animate(pos, tela.Point{}, tela.Spring(), tela.Velocity(tela.Point{X: e.VelocityX, Y: e.VelocityY}))})It makes Animate use a spring. Its type must be the Value’s, and it does not apply to tweens (UseTween, or Duration and Ease alone) nor to Color values, whose components move in a space (sRGB or Oklab, premultiplied) that depends on the two colors: those panic in dev mode and are ignored otherwise.
Example
t := &exampleT{}defer t.close()var x *tela.Value[float32]app := telatest.Mount(t, tela.C(func() tela.Node { x = tela.UseValue[float32](0) return Div(Class("size-8 bg-black"), Style(tela.TranslateFn(func() (float32, float32) { return x.Get(), 0 })))}), telatest.NoSettle())// A flick at rest: the value is already at its target, the velocity// carries it away and the spring brings it back.tela.Animate(x, 0, tela.Stiffness(200), tela.Damping(20), tela.Velocity(float32(600)))var peak float32for range 30 { app.Advance(time.Second / 60) peak = max(peak, x.Get())}app.Advance(2 * time.Second)fmt.Printf("peak %.0f, rest %v\n", peak, x.Get())// Output: peak 19, rest 0type App
Section titled “type App”type App struct { // Title is the window title. Title string // AppID identifies the application to the desktop environment (the // Wayland app_id, the X11 WM_CLASS). Use a reverse-DNS name such as // "com.example.notes". Empty lets the platform pick one. AppID string // Width and Height are the requested size of the window in logical // pixels. Zero means the platform's default size; set both or // neither. Width, Height float32 // MinWidth, MinHeight, MaxWidth and MaxHeight limit the size the user // can give the window; zero is no limit on that side. MinWidth, MinHeight, MaxWidth, MaxHeight float32 // FixedSize keeps the user from resizing the window. FixedSize bool // Frameless removes the OS title bar and borders: the app draws its // own title bar, marked with h.WindowDrag and h.WindowControl. The // window stays resizable at its edges (unless FixedSize). Frameless bool // AlwaysOnTop keeps the window above other windows (not on Wayland). AlwaysOnTop bool // Hidden starts the window hidden (an app that starts in the tray): // [WindowHandle].Show shows it. Hidden bool // Icon is the window's icon (title bar, task bar, alt-tab), the same // picture at several sizes (16 to 256 pixels; the OS picks). Empty is // the default icon (on Linux, the one of the .desktop file of AppID). Icon []image.Image // TitleBar sets the colors of the native title bar and border on // Windows 11; see [TitleBarColors]. The zero value keeps the // system's. Other platforms ignore it. TitleBar TitleBarColors // Backdrop is the system material behind the window (Mica, Mica Alt, // Acrylic) on Windows 11 22H2; see [Backdrop]. The zero value is the // system's choice. Other platforms ignore it. Backdrop Backdrop // Placement is where the window opens: a WindowPlacement saved from // [WindowHandle].Placement in an earlier run, so the window comes back // where the user left it. Its size, when set, wins over Width and // Height. The zero value lets the OS place the window. Placement WindowPlacement // OnClose runs when the user asks to close the main window (its close // button, Alt+F4, a WindowClose control, [WindowHandle].Close). Nil, // the default, quits the app. To keep running in the tray, hide the // window instead; [Quit] ends the app later: // // OnClose: func(w tela.WindowHandle) { w.Hide() }, OnClose func(WindowHandle) // RootClass are Tailwind classes for the root, which fills the // window. Use it to give the window a background ("bg-slate-900") or // a text style; without it the window is white and the text black. // The root is the viewport: content taller or wider than the window // scrolls, unless RootClass sets an overflow ("overflow-hidden" keeps // the window from scrolling; CSS's overflow propagation). RootClass string // Root is the root component: a struct component value (Root: Notes{}) // or a function component made with [C] (Root: Notes(), where Notes // returns tela.C(notes)). It is a // component of its own, so it may use hooks. A [Node] works too, but a // root that uses hooks must be a component. Root Component // ClassicScrollbars draws always-visible classic scrollbars (a // Windows look) that take space next to the content, instead of the // default thin overlay bars that appear while scrolling. The classes // scrollbar-classic and scrollbar-overlay choose per element. ClassicScrollbars bool // InstantScroll makes wheel, keyboard and scrollbar scrolling jump // instead of animating, and touchpad and touch scrolling stop when // the fingers lift instead of flinging. Elements with scroll-smooth // still animate; the class scroll-instant does the same for one // element. InstantScroll bool // ColorScheme is the app's color scheme: Light or Dark override the // system's preference (the dark: classes, UseColorScheme); the zero // value, System, follows it. SetColorScheme changes it while the app // runs. ColorScheme ColorScheme // Theme holds the color tokens (bg-primary, text-muted-foreground), // the base radius and the fonts of the app; nil means DefaultTheme, // so the shadcn/ui tokens always resolve. SetTheme changes it while // the app runs. See [Theme]. Theme *Theme // ClassAliases are class names that stand for class strings, for the // combinations an app repeats: // // ClassAliases: map[string]string{ // "text-muted": "text-sm text-muted-foreground", // "card-title": "text-lg font-semibold dark:text-white", // } // // An alias expands where it appears, so later classes still win over // its classes and its classes over earlier ones. Its variants apply // to every class of the expansion: "hover:card-title" is "hover:text-lg // hover:font-semibold hover:dark:text-white". An alias may use other // aliases; a cycle is reported like an unknown class. An alias wins // over a class of the same name ("text-muted" is also the muted token // as a text color). A key is one class name without variants, spaces // or brackets; Run panics otherwise. Aliases are also suggested for // misspelled classes. ClassAliases map[string]string // Dev turns dev mode on or off. Dev mode reports the mistakes that // compile: unknown classes are printed on standard error; unknown // roles, input types and easings panic with the closest valid name; // hooks called in another order or outside their component panic // with the fix; likely mistakes (lists without keys, nil // dependencies, a Value read while changes are queued...) are printed // as warnings. It costs some speed. // // Nil, the default, means on unless the program is a release build: // go run and go build in a source checkout give development builds, // while a binary built with -trimpath, or installed with go install // pkg@version, is a release build. The environment variable // TELA_DEV=1 or TELA_DEV=0 overrides both Dev and the default. // // off := false // tela.Main(tela.App{Title: "Notes", Root: Notes(), Dev: &off}) Dev *bool // DevState keeps state that lives outside the component tree across // the reloads of tela dev: package variables, controllers, the // settings of a connection. State in hooks, text fields, scroll // offsets and focus is kept without it. See [DevState]; the field is // ignored outside tela dev. DevState DevState}App describes an application window for Run.
tela.Run(tela.App{ Title: "Files", Root: Files{}, // a struct component; Files() for a function ClassicScrollbars: true, // always-visible classic bars (a Windows look) InstantScroll: true, // no scroll animation, no inertia})type Backdrop
Section titled “type Backdrop”type Backdrop = core.BackdropBackdrop is the system material behind a window (App.Backdrop, Window.Backdrop): Mica, Mica Alt or Acrylic on Windows 11.
The zero value, BackdropDefault, leaves the choice to the system. On Windows 11 22H2 (build 22621 and later) the other values apply the material to the native title bar of a decorated window, always; and, for BackdropMica, BackdropMicaAlt and BackdropAcrylic, to the content of the window where the app leaves it transparent. The root has no background by default (see RootClass), so a root without a background class shows the material, a root with a translucent one tints it, and the surfaces the app draws over it (a sidebar with bg-white/60, a card with bg-card) cover it. A root with bg-background hides it:
tela.App{ Backdrop: tela.BackdropMica, RootClass: "bg-background/60", // Mica shows through; elsewhere a plain background Root: Notes{},}The material follows the dark or light title bar, which follows the app’s color scheme. A [Frameless] window with a client-area backdrop extends the window frame over its content (DwmExtendFrameIntoClientArea), which Windows 11 may answer by no longer showing the snap layouts flyout over the app’s maximize button; keep a frameless window without a backdrop if that matters.
Windows 10, Linux and headless ignore Backdrop, and so does Windows 11 before 22H2: the window stays as without it, so an app that leaves its root transparent should still give it a background color for them (a dark: class pair, or a background only where the backdrop is missing). Changing the field of an open Window updates the window.
Backdrop is an alias of core.Backdrop, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type Backdrop = platform.Backdroptype Callback
Section titled “type Callback”type Callback[F any] = core.Callback[F]Callback is a stable handle on the latest function given to UseCallback: cb.Fn() returns one forwarding function, the same on every build, that calls the latest function. It is comparable, so a props struct holding one stays comparable and CP can skip the component that receives it. The zero Callback is tied to no slot: Fn panics, and IsZero reports it, for optional callbacks in props:
if !p.OnClose.IsZero() { p.OnClose.Fn()()}Callback is an alias of core.Callback, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type Callback[F any] struct { // contains filtered or unexported fields}func UseCallback
Section titled “func UseCallback”func UseCallback[F any](fn F) Callback[F]UseCallback stores fn as the latest function of this hook slot and returns the slot’s Callback. cb.Fn() is one function of type F, the same on every build, that calls the latest fn when it is called (React’s useEffectEvent): handlers keep a stable identity and still see the latest build’s values. There are no dependencies. F must be a function type; UseCallback panics otherwise, and for a nil fn.
onSave := tela.UseCallback(func(e tela.MouseEvent) { save(draft) })return Toolbar(ToolbarProps{OnSave: onSave}) // skips while draft changes
// in Toolbar:Button(OnClick(p.OnSave.Fn()), Text("Save"))Call the forwarder on the UI thread (handlers and effects run there); from other goroutines, use Post.
func (Callback) Fn
Section titled “func (Callback) Fn”func (c Callback[F]) Fn() FFn returns the slot’s forwarding function: one function of type F, the same on every build, that calls the latest function given to UseCallback at the time it is called. Call it on the UI thread (event handlers and effects run there); from other goroutines, use Post.
func (Callback) IsZero
Section titled “func (Callback) IsZero”func (c Callback[F]) IsZero() boolIsZero reports whether c is the zero Callback, which is not tied to any UseCallback slot: Fn panics. A Callback left unset in a props struct, or read from a context default without a Provider, is zero.
type ChangeEvent
Section titled “type ChangeEvent”type ChangeEvent = core.ChangeEventChangeEvent is passed to h.OnChange after every edit of a text field’s value, like React’s onChange (the DOM’s input event, not its change on blur): Value is the new value (with the text an IME is composing), InputType, Data and IsComposing describe the edit as in InputEvent. It bubbles, so a Form’s OnChange sees the edits of all its fields.
name, setName := tela.UseState("")Input(Value(name), OnChange(func(e tela.ChangeEvent) { setName.Set(e.Value) }))// the same: Input(Bind(name, setName))ChangeEvent is an alias of core.ChangeEvent, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type ChangeEvent struct { Value string InputType string Data string IsComposing bool // contains filtered or unexported fields}func (ChangeEvent) DefaultPrevented
Section titled “func (ChangeEvent) DefaultPrevented”func (e ChangeEvent) DefaultPrevented() boolDefaultPrevented reports whether a handler called PreventDefault.
func (ChangeEvent) PreventDefault
Section titled “func (ChangeEvent) PreventDefault”func (e ChangeEvent) PreventDefault()PreventDefault marks the event; the edit already happened.
func (ChangeEvent) StopPropagation
Section titled “func (ChangeEvent) StopPropagation”func (e ChangeEvent) StopPropagation()StopPropagation stops the event from bubbling (see MouseEvent).
type Child
Section titled “type Child”type Child = core.ChildChild is what an element takes: a Node (a child), a Prop (h.Class, h.Style, h.Key, h.OnClick…) or any other Component, which becomes a component with its own state. Props and children may be mixed in any order. It has the method set of Component but is a type of its own: a field or parameter of type Child takes props too, one of type Component is for what renders. Passing a string or a number is a compile error; wrap text in h.Text. The compiler names the internal type behind the alias:
cannot use "hello" (constant of type string) as tela.Child value inargument to Div: string does not implement core.Child (missing methodBuild)means Div(“hello”) should be Div(Text(“hello”)).
Child is an alias of core.Child, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type Child interface { Build() Node}type Color
Section titled “type Color”type Color = gfx.ColorColor is a non-premultiplied color with float32 components R, G, B and A. A (opacity) is in [0, 1]. R, G and B are extended sRGB, like CSS Color 4: they are in [0, 1] for colors inside the sRGB gamut, while a color outside it, such as a third of the Tailwind palette once converted from OKLCH, keeps components below 0 or above 1 and is clipped when painted, as browsers do. Clamp before converting to 8-bit values. The zero value is transparent black.
Color is an alias of an internal type: use its fields and methods (WithAlpha, MulAlpha, String…) and the constructors Hex, RGB, RGBA and OKLCH.
Color is an alias of gfx.Color, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type Color struct{ R, G, B, A float32 }func Hex
Section titled “func Hex”func Hex(s string) ColorHex parses a CSS hex color: “#rgb”, “#rgba”, “#rrggbb” or “#rrggbbaa”. It panics with the reason when s is not valid, since a literal that does not parse is a programmer error.
tela.Hex("#1e1e2e")Example
c := tela.Hex("#1e1e2e")fmt.Println(c.R == tela.RGB(30, 30, 46).R, c)// Output: true #1e1e2efunc OKLCH
Section titled “func OKLCH”func OKLCH(l, c, h float32) ColorOKLCH returns the opaque color with OKLCH lightness l (0 to 1), chroma c (about 0 to 0.4) and hue h in degrees, the notation of the Tailwind v4 palette: tela.OKLCH(0.637, 0.237, 25.331) is red-500. Use WithAlpha for transparency. The result is not gamut-mapped (see Color).
func RGB
Section titled “func RGB”func RGB(r, g, b uint8) ColorRGB returns the opaque color with the given 8-bit components.
func RGBA
Section titled “func RGBA”func RGBA(r, g, b uint8, a float32) ColorRGBA returns the color with the given 8-bit components and an alpha from 0 (transparent) to 1 (opaque), like CSS rgba(r, g, b, a).
func (Color) Clamp
Section titled “func (Color) Clamp”func (c Color) Clamp() ColorClamp returns c with every component clamped to [0, 1]. NaN becomes 0. For an extended sRGB color this per-channel clip is what browsers paint.
func (Color) IsFinite
Section titled “func (Color) IsFinite”func (c Color) IsFinite() boolIsFinite reports whether all four components are finite.
func (Color) IsOpaque
Section titled “func (Color) IsOpaque”func (c Color) IsOpaque() boolIsOpaque reports whether A >= 1.
func (Color) MulAlpha
Section titled “func (Color) MulAlpha”func (c Color) MulAlpha(f float32) ColorMulAlpha returns c with its alpha multiplied by f (Tailwind’s “bg-white/15” is White.MulAlpha(0.15)).
func (Color) NRGBA8
Section titled “func (Color) NRGBA8”func (c Color) NRGBA8() color.NRGBANRGBA8 returns the non-premultiplied 8-bit color, rounded to nearest.
func (Color) Premul8
Section titled “func (Color) Premul8”func (c Color) Premul8() color.RGBAPremul8 returns the premultiplied 8-bit color, with every channel rounded to nearest (half up) from the exact float value, never by premultiplying already-rounded bytes. The result satisfies R,G,B <= A.
func (Color) Premultiplied
Section titled “func (Color) Premultiplied”func (c Color) Premultiplied() (r, g, b, a float32)Premultiplied returns the premultiplied components (R*A, G*A, B*A, A) as floats in [0, 1].
func (Color) String
Section titled “func (Color) String”func (c Color) String() stringString returns “#rrggbb” for opaque colors and “#rrggbbaa” otherwise, with components rounded to 8 bits.
func (Color) ToOKLCH
Section titled “func (Color) ToOKLCH”func (c Color) ToOKLCH() (l, ch, h float32)ToOKLCH returns the OKLCH coordinates of c (alpha is ignored). The hue h is in degrees in [0, 360); it is 0 for achromatic colors.
func (Color) ToOklab
Section titled “func (Color) ToOklab”func (c Color) ToOklab() (l, a, b float32)ToOklab returns the Oklab coordinates of c (alpha is ignored), extended sRGB components included. l is in [0, 1] for in-gamut colors; a and b are roughly in [-0.4, 0.4].
func (Color) WithAlpha
Section titled “func (Color) WithAlpha”func (c Color) WithAlpha(a float32) ColorWithAlpha returns c with its alpha replaced by a.
type ColorScheme
Section titled “type ColorScheme”type ColorScheme = core.ColorSchemeColorScheme is a color scheme: what the app asks for (System, Light or Dark) in App.ColorScheme and SetColorScheme, and the effective scheme UseColorScheme returns (Light or Dark). The dark: classes apply in the effective Dark scheme.
ColorScheme is an alias of core.ColorScheme, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type ColorScheme uint8const ( // ColorSchemeSystem follows the system's preference (the zero // value). ColorSchemeSystem ColorScheme = iota // ColorSchemeLight is the light scheme: dark: variants do not apply. ColorSchemeLight // ColorSchemeDark is the dark scheme: dark: variants apply. ColorSchemeDark)const ( // System follows the system's light or dark preference. It is the // zero value, so an [App] follows the system unless it sets // ColorScheme. System ColorScheme = core.ColorSchemeSystem // Light is the light scheme: dark: classes do not apply. Light ColorScheme = core.ColorSchemeLight // Dark is the dark scheme: dark: classes apply. Dark ColorScheme = core.ColorSchemeDark)func UseColorScheme
Section titled “func UseColorScheme”func UseColorScheme() ColorSchemeUseColorScheme returns the color scheme at the component’s position, Light or Dark: the one the nearest element above it with an h.Scheme prop gives, else the app’s, the one the app set (App.ColorScheme, SetColorScheme) or, with System, the system’s preference. The component builds again when it changes, like with a state hook. It is a hook: call it at the top level of a component.
func Logo() tela.Node { src := lightLogo if tela.UseColorScheme() == tela.Dark { src = darkLogo } return Img(SrcImage(src), Alt("Tela"))}Classes do not need it: dark:bg-slate-900 already follows the scheme.
Example
theme := func() tela.Node { name := "light" if tela.UseColorScheme() == tela.Dark { name = "dark" } return P(Textf("Theme: %s", name))}// The system prefers dark (telatest.Dark), the app follows it.yaml, _ := telatest.AriaSnapshot(tela.C(theme), telatest.Dark())fmt.Println(yaml)// The app overrides the system (tela.App.ColorScheme).yaml, _ = telatest.AriaSnapshot(tela.C(theme), telatest.Dark(), telatest.ColorScheme(tela.Light))fmt.Println(yaml)// Output:// - paragraph: "Theme: dark"// - paragraph: "Theme: light"func (ColorScheme) String
Section titled “func (ColorScheme) String”func (s ColorScheme) String() stringtype Component
Section titled “type Component”type Component = core.CompComponent is a unit of UI with its own state boundary: a value whose Build method returns what it renders. Build must use a value receiver.
type Card struct { Title string OnOpen tela.Callback[func()] Children tela.Component // children are an ordinary field}
func (c Card) Build() tela.Node { open, setOpen := tela.UseState(false) return Div(Class("rounded-xl border p-4"), H2(OnClick(func(tela.MouseEvent) { setOpen.Set(!open) }), Text(c.Title)), If(open, c.Children))}
Div(Card{Title: "Inbox", Children: Fragment(Text("a"), Span(Text("b")))})Every Component value given to an element as a child is a component of its own, with its own hook state: hooks called in Build (and in the function literals inside it) belong to it. Its identity among its siblings is its type and its key (WithKey), so at one position a value of the same type keeps the state of the previous build and a value of another type mounts anew. When its parent builds again, its build is skipped if the new value equals the previous one and no state, Value or context it read changed, as with CP. The comparison is ==, field by field, and never panics: a value that cannot be compared (a struct holding a slice, a map or a func, or a field of interface type holding one) counts as changed, so it always builds. A Node in a field compares by identity: a fresh h.Div(…) is a change, a node kept in a UseMemo is not. Pass Callback values instead of funcs to keep a component skippable.
Calling Build directly (Card{}.Build() inside another component) runs it inside the caller, whose hook slots it would take: dev mode panics and says to pass Card{…} as a child instead. Where a Node is expected (the result of a function component, an h.Map item), give the value to h.Fragment, or key it with WithKey. h.If takes a struct component as is, If(loading, Spinner{}), and renders nothing when the condition is false; it returns a Child, so a function that returns a Node wraps it: Fragment(If(…)).
In dev mode (see App.Dev) a pointer (Div(&Card{})) panics, since a component is a value that Tela compares, and so does a Prop held by a field of type Component (Card{Children: Class(“p-4”)}): Go cannot tell it from a component at compile time, and given to an element it would apply to that element. A field that is meant to take props too is declared as Child.
Node and Prop implement Component as well; a function component becomes one with C, CP or Memo.
Component is an alias of core.Comp, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type Comp interface { Build() Node}Example
t := &exampleT{}defer t.close()app := telatest.Mount(t, Div(Class("flex flex-col gap-2"), Panel{Title: "Inbox", Children: Fragment(P(Text("2 new")), P(Text("from Ada")))}, Panel{Title: "Archive", Children: P(Text("empty"))}))// Each Panel has its own state: this closes the first one only.app.Click(telatest.ByRole("button", "Inbox"))fmt.Println(app.AriaSnapshot())// Output:// - button "Inbox"// - button "Archive" [expanded]// - paragraph: emptyExample (skipping)
t := &exampleT{}defer t.close()counts := map[string]int{}builds := &countspage := func() tela.Node { clicks, setClicks := tela.UseState(0) return Div( Button(OnClick(func(tela.MouseEvent) { setClicks.Set(clicks + 1) }), Text("Click")), Badge{Label: "Inbox", Count: 3, builds: builds}, // equal on every build: skipped Badge{Label: "Clicks", Count: clicks, builds: builds}, // changes: built again )}app := telatest.Mount(t, tela.C(page))app.Click(telatest.ByRole("button", "Click"))app.Click(telatest.ByRole("button", "Click"))fmt.Println(counts["Inbox"], counts["Clicks"])// Output: 1 3type CompositionEvent
Section titled “type CompositionEvent”type CompositionEvent = core.CompositionEventCompositionEvent is passed to h.OnCompositionStart, h.OnCompositionUpdate and h.OnCompositionEnd while an input method (IME: Japanese, Chinese, Korean…) composes text in a text field: Data is the text being composed. It bubbles.
CompositionEvent is an alias of core.CompositionEvent, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type CompositionEvent struct { Data string // contains filtered or unexported fields}func (CompositionEvent) DefaultPrevented
Section titled “func (CompositionEvent) DefaultPrevented”func (e CompositionEvent) DefaultPrevented() boolDefaultPrevented reports whether a handler called PreventDefault.
func (CompositionEvent) PreventDefault
Section titled “func (CompositionEvent) PreventDefault”func (e CompositionEvent) PreventDefault()PreventDefault marks the event; compositions cannot be canceled.
func (CompositionEvent) StopPropagation
Section titled “func (CompositionEvent) StopPropagation”func (e CompositionEvent) StopPropagation()StopPropagation stops the event from bubbling (see MouseEvent).
type Context
Section titled “type Context”type Context[T any] = core.Context[T]Context passes a value down the tree without props: see CreateContext.
Context is an alias of core.Context, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type Context[T any] struct { // contains filtered or unexported fields}func CreateContext
Section titled “func CreateContext”func CreateContext[T any](def T) *Context[T]CreateContext returns a new context whose UseContext outside any Provider returns def. Create contexts once, at package level.
var Theme = tela.CreateContext("light")
func App() tela.Node { theme, _ := tela.UseState("dark") return Theme.Provider(theme, Page())}ctx.Provider(value, children…) returns a node without a box that gives value to its children’s subtrees (only h.Key is accepted as a prop). When the Provider gets a value that is not == to the previous one (values that cannot be compared always count as changed), only the components that read it with UseContext build again, even when the components between them skip their build.
func (*Context) Provider
Section titled “func (*Context) Provider”func (c *Context[T]) Provider(value T, children ...Child) NodeProvider returns a node that gives value to the UseContext calls of its children’s subtrees. It has no box: the children become children of the provider’s parent, like a Fragment, and only Key is accepted as a prop.
type DevState
Section titled “type DevState”type DevState struct { // Save returns the state to keep. Nil keeps nothing. Save func() ([]byte, error) // Restore receives what Save returned in the previous process. Nil // ignores it. Restore func([]byte) error}DevState is the state of an app that lives outside its component tree, to keep across the reloads of tela dev: package variables, a controller object, the settings of a connection. tela dev rebuilds the app on every save and runs the new build as a new process; the state of hooks, text fields, scroll offsets and focus is carried over by Tela itself (it is in the tree), and DevState carries the rest.
Before it stops the old process, tela dev calls Save and keeps the bytes (encode them with encoding/gob, JSON or anything else). In the new process it calls Restore with those bytes before the root mounts, so the first build already sees the restored values. A Save or Restore that returns an error or panics is reported as a warning and that state starts fresh; Restore is not called when Save returned no bytes, nor on the first start or after a restart with fresh state (the R key, –no-state). Both run on the UI thread, so they need no locking against the components.
Outside tela dev (tela.Main, tela snapshot, tests, release builds) DevState is ignored and neither function is called.
To keep the save and restore code, and encoding/gob, out of release builds, give the field a variable that only a file built with the teladev tag assigns:
var devState tela.DevState
func main() { tela.Main(tela.App{Title: "Notes", Root: Notes{}, DevState: devState})}
// devstate_dev.go//go:build teladev
func init() { devState = tela.DevState{ Save: func() ([]byte, error) { return json.Marshal(current) }, Restore: func(b []byte) error { return json.Unmarshal(b, ¤t) }, }}tela dev builds with that tag; go build and go install do not.
Example
A variable outside the component tree survives a tela dev reload when the app saves and restores it. The example plays both processes: in a real app tela dev calls Save before it stops the old build and Restore before the new one mounts, and the functions live in a file built only with the teladev tag (see tela.DevState).
selected := "inbox" // lives in a package variable, not in a hook
devState := tela.DevState{ Save: func() ([]byte, error) { return json.Marshal(selected) }, Restore: func(b []byte) error { return json.Unmarshal(b, &selected) },}_ = tela.App{Title: "Mail", DevState: devState}
saved, _ := devState.Save() // the old process, before it stopsselected = "" // the new process starts with the zero value...devState.Restore(saved) // ...and gets the state back before it mountsfmt.Println(selected)// Output: inboxtype Dispatcher
Section titled “type Dispatcher”type Dispatcher[A any] = core.Dispatcher[A]Dispatcher sends actions to one UseReducer slot: d.Dispatch(action). Like Setter, it is comparable, stable for its slot and safe from any goroutine.
Dispatcher is an alias of core.Dispatcher, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type Dispatcher[A any] struct { // contains filtered or unexported fields}func UseReducer
Section titled “func UseReducer”func UseReducer[S, A any](reducer func(S, A) S, initial S) (S, Dispatcher[A])UseReducer returns the state of this hook slot and a Dispatcher whose actions update it with reducer (React’s useReducer). The first build stores initial. Queued actions apply in order on the UI thread with the reducer of the latest build, each receiving the state left by the previous one; reducer must be pure. For comparable states, a result == to the current state does not rebuild.
type action struct{ kind string }
func reduce(n int, a action) int { switch a.kind { case "inc": return n + 1 case "reset": return 0 } return n}
count, d := tela.UseReducer(reduce, 0)d.Dispatch(action{"inc"})func (Dispatcher) Dispatch
Section titled “func (Dispatcher) Dispatch”func (d Dispatcher[A]) Dispatch(a A)Dispatch queues action a. When the update applies on the UI thread, the reducer of the latest build computes the new state from the state left by the previous queued update; for comparable states, a result == to the current state does not rebuild.
type DragEvent
Section titled “type DragEvent”type DragEvent = core.DragEventDragEvent is passed to h.OnDragStart, h.OnDrag and h.OnDragEnd: the position, the movement since the previous drag event (DeltaX, DeltaY) and since the press (OffsetX, OffsetY), and the velocity in pixels per second (VelocityX, VelocityY; meaningful at the end).
DragEvent is an alias of core.DragEvent, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type DragEvent struct { // X and Y are the position in the window, LocalX and LocalY relative // to the border box of the element (see MouseEvent). X, Y, LocalX, LocalY float32 // DeltaX and DeltaY are the movement since the previous drag event // (since the press for OnDragStart). DeltaX, DeltaY float32 // OffsetX and OffsetY are the movement since the press: an element // moved by them follows the pointer exactly. OffsetX, OffsetY float32 // VelocityX and VelocityY are the pointer velocity in logical pixels // per second, from the last 100 ms of moves; meaningful at // OnDragEnd (a fling), zero when the pointer stopped before the // release or the drag was cancelled. VelocityX, VelocityY float32 // Button is the button of the drag (MouseButtonLeft). Button MouseButton // Modifier keys held during the event. Shift, Ctrl, Alt, Meta bool // contains filtered or unexported fields}func (DragEvent) DefaultPrevented
Section titled “func (DragEvent) DefaultPrevented”func (e DragEvent) DefaultPrevented() boolDefaultPrevented reports whether a handler called PreventDefault.
func (DragEvent) PreventDefault
Section titled “func (DragEvent) PreventDefault”func (e DragEvent) PreventDefault()PreventDefault marks the event (see MouseEvent).
func (DragEvent) StopPropagation
Section titled “func (DragEvent) StopPropagation”func (e DragEvent) StopPropagation()StopPropagation does nothing for drags, which go to one element; it exists for symmetry with the other events.
type Easing
Section titled “type Easing”type Easing stringEasing is a CSS <easing-function> as a string: one of the constants EaseLinear, EaseIn, EaseOut and EaseInOut, the keywords “ease”, “step-start” and “step-end”, CubicBezier, or “steps(n[, position])”. It is a string type, so a literal such as “ease-out” keeps compiling where an Easing is wanted.
const ( // EaseLinear is "linear": constant speed. EaseLinear Easing = "linear" // EaseIn is "ease-in", cubic-bezier(0.42, 0, 1, 1): starts slow. EaseIn Easing = "ease-in" // EaseOut is "ease-out", cubic-bezier(0, 0, 0.58, 1): ends slow. EaseOut Easing = "ease-out" // EaseInOut is "ease-in-out", cubic-bezier(0.42, 0, 0.58, 1): slow at // both ends. EaseInOut Easing = "ease-in-out")The easing keywords of CSS Easing Functions Level 1 that Tailwind and Motion also name. They are CSS’s curves: Tailwind’s ease-out utility is CubicBezier(0, 0, 0.2, 1), which is not EaseOut. The default of a tween is CSS’s “ease”, which has no constant.
Example
// The constants and string literals are both Easings; a variable// that holds a CSS easing converts with tela.Easing(s).opts := []tela.AnimationOption{ tela.Ease(tela.EaseInOut), tela.Ease("ease-out"), tela.Ease(tela.Easing("steps(4, jump-end)")),}fmt.Println(len(opts), tela.EaseLinear, tela.EaseIn, tela.EaseOut, tela.EaseInOut)// Output: 3 linear ease-in ease-out ease-in-outfunc CubicBezier
Section titled “func CubicBezier”func CubicBezier(x1, y1, x2, y2 float32) EasingCubicBezier returns the easing cubic-bezier(x1, y1, x2, y2): a Bezier curve from (0, 0) to (1, 1) with those control points. x1 and x2 must be from 0 to 1 (y1 and y2 may overshoot, for a bounce); Ease panics in dev mode otherwise.
tela.Ease(tela.CubicBezier(0, 0, 0.2, 1)) // Tailwind's ease-outExample
// Tailwind's ease-out utility, and a curve that overshoots.fmt.Println(tela.CubicBezier(0, 0, 0.2, 1))fmt.Println(tela.CubicBezier(0.34, 1.56, 0.64, 1))_ = tela.Ease(tela.CubicBezier(0, 0, 0.2, 1))// Output:// cubic-bezier(0, 0, 0.2, 1)// cubic-bezier(0.34, 1.56, 0.64, 1)type ElementRef
Section titled “type ElementRef”type ElementRef = core.ElementRefElementRef is a handle on the element it is attached to with h.Ref, returned by UseElementRef: the same comparable value on every build. Its methods act on the element while it is mounted and do nothing (or report false) otherwise; call them from event handlers and effects.
- Focus focuses the element, if it is focusable (a Button, an h.Input or h.Textarea, or an element with h.TabIndex, not disabled or hidden).
- Blur removes the focus from the element if it has it.
- Focused reports whether the element has the focus of its window.
- Click clicks the element like HTML’s element.click(): a click event with the primary button, at the center of the element, is dispatched at it (OnClick handlers run and it bubbles; the hooks of package aria see a virtual press), then, unless a handler prevented it, the activation behavior runs: a Button in a Form submits it or resets it by its h.Type, a Label focuses its control and clicks it. No pointer events and no focus change. A disabled or unmounted element ignores it. Call it in a handler or an effect: the state it sets is applied and built by the event or the frame that is running.
- ScrollTo(x, y) and ScrollBy(dx, dy) scroll a scrolling element (overflow auto, scroll or hidden) to or by offsets, clamped to its content; ScrollOffset returns its offsets (the DOM’s scrollLeft and scrollTop; in a right-to-left element x is 0 at the right and negative toward the left). They jump, or animate when the element has scroll-smooth, and do nothing (or return 0) for other elements.
- ScrollIntoView scrolls every scrolling ancestor of the element so that it is visible, each as little as possible (block and inline “nearest”).
- Bounds returns the element’s border box in window coordinates as a
Rect, moved by scrolling and transforms (getBoundingClientRect); the zero Rect before it is laid out.UseBoundsfollows it in aValue. - ScrollToIndex(i, align) scrolls an h.VirtualList to item i, placed as
ScrollAlignsays, and keeps it there while the items around it are measured; it does nothing for other elements. - Text fields (h.Input, h.Textarea): Value returns the value (the DOM’s input.value: mainly for uncontrolled fields), Select selects all of it, SetSelectionRange(start, end) selects part of it and SelectionRange returns the selection, in UTF-8 byte offsets of the value (HTML’s select(), setSelectionRange, selectionStart and selectionEnd); on other elements they do nothing and return “” or 0, 0.
For example, “/” focuses a search box:
search := tela.UseElementRef()return Div(OnKeyDown(func(e tela.KeyboardEvent) { if e.Key == "/" && !search.Focused() { e.PreventDefault() search.Focus() search.Select() } }), Input(Ref(search), Type("search"), Placeholder("Search"), Class("rounded-md border px-2 py-1")),)A “back to top” button for a list:
list := tela.UseElementRef()return Div(Class("relative"), Div(Ref(list), Class("h-96 overflow-y-auto scroll-smooth"), rows), Button(OnClick(func(tela.MouseEvent) { list.ScrollTo(0, 0) }), Text("Top")))ElementRef is an alias of core.ElementRef, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type ElementRef struct { // contains filtered or unexported fields}func UseElementRef
Section titled “func UseElementRef”func UseElementRef() ElementRefUseElementRef returns the ElementRef of this hook slot, the same on every build. Attach it to an element with h.Ref, then act on the element from handlers and effects (React’s useRef with a DOM element):
func Search() tela.Node { input := tela.UseElementRef() tela.UseMount(func() func() { input.Focus() return nil }) return Div(Ref(input), TabIndex(0), Class("rounded-md p-2 focus:ring-2"), Text("Search"))}func (ElementRef) Blur
Section titled “func (ElementRef) Blur”func (r ElementRef) Blur()Blur removes the focus from the element if it has it (HTML’s blur()): nothing is focused afterwards. Inside an active containing focus scope it does nothing: the scope keeps the focus (React Aria’s FocusScope contain focuses the element again).
func (ElementRef) Bounds
Section titled “func (ElementRef) Bounds”func (r ElementRef) Bounds() RectBounds returns the border box of the element in window coordinates and logical pixels, as it was last laid out and painted: moved by the scroll offsets of the containers around it and by its own transform and those of its ancestors, as the axis-aligned bounding box of the transformed box (getBoundingClientRect). The window’s top-left corner is (0, 0). An inline element (a Span in a paragraph) has the union of its fragments, and an element with display: contents that of its children. It is the zero Rect for an element that is not mounted, is display: none, or has not been laid out yet. Call it from event handlers and effects; UseBounds gives a Value that follows it.
func (ElementRef) Click
Section titled “func (ElementRef) Click”func (r ElementRef) Click()Click clicks the element like HTML’s element.click(): a click event (the primary button, a click count of 1, at the center of the element’s bounds, made by no pointer: the hooks of package aria see a virtual press) is dispatched at it and bubbles, then, unless a handler prevented it, the activation behavior of the Button or Label at or above it runs (a Button in a Form submits it or resets it by its Type; a Label focuses its control and clicks it). There are no pointer events, no :active state and no focus change of its own. It does nothing for an unmounted element or a disabled one (or one inside a disabled element).
Call it on the UI thread, in a handler or an effect: the updates the click makes are applied and built by the event or the frame that is running (after the passive effects, by the host’s next step, which the updates wake); called from elsewhere on the UI thread, it applies and builds them before it returns, as a real click does.
func (ElementRef) Focus
Section titled “func (ElementRef) Focus”func (r ElementRef) Focus()Focus focuses the element, if it is focusable (HTML’s focus()): OnBlur runs on the element that loses the focus and OnFocus on this one, before it returns. Called from a handler or an effect, the updates those handlers make are applied and built by the event or the frame that is running (after the passive effects, by the host’s next step), as for Click.
func (ElementRef) Focused
Section titled “func (ElementRef) Focused”func (r ElementRef) Focused() boolFocused reports whether the element is the focused element of its window (also while the window itself does not have keyboard focus).
func (ElementRef) ScrollBy
Section titled “func (ElementRef) ScrollBy”func (r ElementRef) ScrollBy(dx, dy float32)ScrollBy scrolls the element by (dx, dy) from its current offsets (see ScrollTo).
func (ElementRef) ScrollIntoView
Section titled “func (ElementRef) ScrollIntoView”func (r ElementRef) ScrollIntoView()ScrollIntoView scrolls every scroll container around the element so that it is visible, moving each as little as possible (CSSOM View’s scrollIntoView with block and inline “nearest”); each container jumps or animates as its scroll-behavior says. It does nothing when the element is not mounted or not displayed. Called from a layout effect, it scrolls with the layout and extents of that frame, before paint.
func (ElementRef) ScrollOffset
Section titled “func (ElementRef) ScrollOffset”func (r ElementRef) ScrollOffset() (x, y float32)ScrollOffset returns the element’s scroll offsets (the DOM’s scrollLeft and scrollTop): zero when it is not a scroll container or not mounted. During a smooth scroll it is the current, animated position. In a right-to-left container x is 0 at the right and negative toward the left.
func (ElementRef) ScrollTo
Section titled “func (ElementRef) ScrollTo”func (r ElementRef) ScrollTo(x, y float32)ScrollTo scrolls the element to offsets (x, y), clamped to its extents (CSSOM View’s scrollTo): at once, or animated when it has scroll-smooth. It does nothing for an element that is not a scroll container (overflow auto, scroll or hidden) or not mounted. In a right-to-left container x is 0 at the right and negative toward the left, like the DOM’s scrollLeft. Called from a layout effect, it applies in the same frame with the extents of that frame’s layout, before paint.
func (ElementRef) ScrollToIndex
Section titled “func (ElementRef) ScrollToIndex”func (r ElementRef) ScrollToIndex(i int, align ScrollAlign)ScrollToIndex scrolls a VirtualList so that item i is in view, placed as align says (TanStack Virtual’s scrollToIndex; see the comment at the top of virtual.go): at once, or animated when the list has scroll-smooth, like ScrollTo. i is clamped to the items. It does nothing when the element is not a mounted VirtualList, has no items or does not scroll (overflow-visible).
func (ElementRef) Select
Section titled “func (ElementRef) Select”func (r ElementRef) Select()Select selects the whole value of the text field the ref is attached to (HTML’s select()) and fires OnSelect; it does nothing on other elements.
func (ElementRef) SelectionRange
Section titled “func (ElementRef) SelectionRange”func (r ElementRef) SelectionRange() (start, end int)SelectionRange returns the selection of the text field the ref is attached to in UTF-8 byte offsets of its value, ordered (HTML’s selectionStart and selectionEnd); 0, 0 for other elements.
func (ElementRef) SetSelectionRange
Section titled “func (ElementRef) SetSelectionRange”func (r ElementRef) SetSelectionRange(start, end int)SetSelectionRange selects the bytes [start, end) of the value of the text field the ref is attached to (UTF-8 byte offsets, clamped to the value and moved to grapheme cluster boundaries; start > end selects nothing at end), as HTML’s setSelectionRange, and fires OnSelect when it changed. It does nothing on other elements.
func (ElementRef) Value
Section titled “func (ElementRef) Value”func (r ElementRef) Value() stringValue returns the value of the text field the ref is attached to (with the text an IME is composing, as the DOM’s input.value), “” for other elements: mainly for uncontrolled fields.
type FocusEvent
Section titled “type FocusEvent”type FocusEvent = core.FocusEventFocusEvent is passed to h.OnFocus and h.OnBlur. Like React’s onFocus and onBlur, focus events bubble: a container’s OnFocus also runs when one of its descendants gains the focus.
Div(OnFocus(func(tela.FocusEvent) { setEditing.Set(true) }), OnBlur(func(tela.FocusEvent) { setEditing.Set(false) }), ...)FocusEvent is an alias of core.FocusEvent, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type FocusEvent struct { // contains filtered or unexported fields}func (FocusEvent) DefaultPrevented
Section titled “func (FocusEvent) DefaultPrevented”func (e FocusEvent) DefaultPrevented() boolDefaultPrevented reports whether a handler called PreventDefault.
func (FocusEvent) PreventDefault
Section titled “func (FocusEvent) PreventDefault”func (e FocusEvent) PreventDefault()PreventDefault marks the event; focus events have no default action to cancel (the focus has already moved).
func (FocusEvent) StopPropagation
Section titled “func (FocusEvent) StopPropagation”func (e FocusEvent) StopPropagation()StopPropagation stops the event from bubbling to the ancestors.
type Gradient
Section titled “type Gradient”type Gradient = style.GradientGradient is a background gradient; build one with LinearGradient.
Gradient is an alias of style.Gradient, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type Gradient struct { Kind GradientKind
// Angle is the direction of a linear gradient in degrees (0 is up, 90 // is to the right) when Corner is CornerNone, and the start angle // ("from") of a conic gradient. Angle float32 Corner Corner
// Radial shape, size and (for SizeExplicit) radii; a circle uses // Radius[0] only. Shape RadialShape Size RadialSize Radius [2]LP
// Center is the position of a radial or conic gradient inside the // box, from its top-left corner. The default is 50% 50%. CenterX, CenterY LP
// Interp is the color space of the interpolation. The zero value is // Oklab, the default of Tailwind's named gradient utilities; gradients // written as CSS functions default to sRGB, as in CSS (ADR-158). Interp gfx.ColorSpace
Stops []ColorStop}func LinearGradient
Section titled “func LinearGradient”func LinearGradient(angleDeg float32, stops ...GradientStop) GradientLinearGradient returns a linear gradient in the direction of angleDeg: 0 points up, 90 to the right and 180 (CSS’s default) down. Colors interpolate in Oklab, like Tailwind v4.
func (*Gradient) Paint
Section titled “func (*Gradient) Paint”func (g *Gradient) Paint(box gfx.Rect) gfx.PaintPaint returns the paint of the gradient for a box with the given rectangle, in the coordinates of that rectangle (the color of a point of the gradient is the same as CSS paints in a box of this size).
type GradientStop
Section titled “type GradientStop”type GradientStop = style.ColorStopGradientStop is a color stop of a gradient; build one with Stop or StopAt.
GradientStop is an alias of style.ColorStop, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type ColorStop struct { Color gfx.Color Pos StopPos}func Stop
Section titled “func Stop”func Stop(c Color) GradientStopStop returns a gradient stop whose position is spread automatically between its neighbors, as in CSS.
func StopAt
Section titled “func StopAt”func StopAt(c Color, percent float32) GradientStopStopAt returns a gradient stop at a percentage (0 to 100) of the gradient line.
type Icon
Section titled “type Icon”type Icon struct { SVG string}Icon is an SVG icon, shown with h.Icon. Its SVG field holds the text of an SVG document, so that icons can be package-level data:
var Check = tela.Icon{SVG: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M20 6 9 17l-5-5"/></svg>`}The document is parsed the first time an icon with that text is drawn and the result is cached by the text for the life of the process (in a cache bounded by size), so drawing it again, at any size or color, never parses it again. Icon is comparable. ParseSVG and MustSVG check the text when the icon is created.
Icons are drawn as vectors at the device scale, with currentColor as the element’s text color; see h.Icon.
func MustSVG
Section titled “func MustSVG”func MustSVG(data []byte) IconMustSVG is ParseSVG for documents known to be valid, such as embedded files: it panics on error.
//go:embed logo.svgvar logoSVG []bytevar Logo = tela.MustSVG(logoSVG)func ParseSVG
Section titled “func ParseSVG”func ParseSVG(data []byte) (Icon, error)ParseSVG parses data as an SVG document and returns it as an Icon. The parsed document is cached, so the first draw does not parse it again. It returns the parse error of malformed XML, a root that is not svg, or a document beyond Tela’s limits on size.
type InputEvent
Section titled “type InputEvent”type InputEvent = core.InputEventInputEvent is passed to h.OnBeforeInput before a text field’s value changes by an edit of the user (the DOM’s beforeinput): InputType names the edit with the W3C Input Events names (“insertText”, “insertFromPaste”, “insertLineBreak”, “deleteContentBackward”, “deleteWordBackward”, “deleteByCut”, “historyUndo”, “insertCompositionText”…), Data is the inserted text (empty for deletions), IsComposing reports an IME composition. PreventDefault cancels the edit, except during a composition and for the text an IME deletes around the caret. It bubbles.
// Digits only.Input(OnBeforeInput(func(e tela.InputEvent) { if strings.Trim(e.Data, "0123456789") != "" { e.PreventDefault() }}))InputEvent is an alias of core.InputEvent, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type InputEvent struct { InputType string Data string IsComposing bool // contains filtered or unexported fields}func (InputEvent) DefaultPrevented
Section titled “func (InputEvent) DefaultPrevented”func (e InputEvent) DefaultPrevented() boolDefaultPrevented reports whether a handler called PreventDefault.
func (InputEvent) PreventDefault
Section titled “func (InputEvent) PreventDefault”func (e InputEvent) PreventDefault()PreventDefault cancels the edit (not during a composition, nor an IME’s deletion around the caret).
func (InputEvent) StopPropagation
Section titled “func (InputEvent) StopPropagation”func (e InputEvent) StopPropagation()StopPropagation stops the event from bubbling (see MouseEvent).
type KeyCode
Section titled “type KeyCode”type KeyCode = core.CodeValueKeyCode is a physical key, the type of KeyboardEvent.Code: its position on the keyboard whatever the layout (a W3C KeyboardEvent code value), one of the Code constants. Use it for shortcuts that depend on the position (WASD), and Key for those that depend on the meaning (Ctrl+Z):
if e.Code == tela.CodeKeyW || e.Code == "ArrowUp" { moveUp() }KeyCode is an alias of core.CodeValue, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type CodeValue stringconst ( // CodeUnidentified is a key without a W3C code value. CodeUnidentified KeyCode = "Unidentified"
// Writing system keys (alphanumeric section). The comments give the // US layout label. CodeBackquote KeyCode = "Backquote" // `~ (半角/全角 on Japanese keyboards) CodeBackslash KeyCode = "Backslash" // \| (# on UK layouts, row C) CodeBracketLeft KeyCode = "BracketLeft" // [{ CodeBracketRight KeyCode = "BracketRight" // ]} CodeComma KeyCode = "Comma" // ,< CodeDigit0 KeyCode = "Digit0" // 0) CodeDigit1 KeyCode = "Digit1" // 1! CodeDigit2 KeyCode = "Digit2" // 2@ CodeDigit3 KeyCode = "Digit3" // 3# CodeDigit4 KeyCode = "Digit4" // 4$ CodeDigit5 KeyCode = "Digit5" // 5% CodeDigit6 KeyCode = "Digit6" // 6^ CodeDigit7 KeyCode = "Digit7" // 7& CodeDigit8 KeyCode = "Digit8" // 8* CodeDigit9 KeyCode = "Digit9" // 9( CodeEqual KeyCode = "Equal" // =+ CodeIntlBackslash KeyCode = "IntlBackslash" // between left Shift and Z on ISO keyboards CodeIntlRo KeyCode = "IntlRo" // ろ, between / and right Shift (Japanese) CodeIntlYen KeyCode = "IntlYen" // ¥, between = and Backspace (Japanese) CodeKeyA KeyCode = "KeyA" CodeKeyB KeyCode = "KeyB" CodeKeyC KeyCode = "KeyC" CodeKeyD KeyCode = "KeyD" CodeKeyE KeyCode = "KeyE" CodeKeyF KeyCode = "KeyF" CodeKeyG KeyCode = "KeyG" CodeKeyH KeyCode = "KeyH" CodeKeyI KeyCode = "KeyI" CodeKeyJ KeyCode = "KeyJ" CodeKeyK KeyCode = "KeyK" CodeKeyL KeyCode = "KeyL" CodeKeyM KeyCode = "KeyM" CodeKeyN KeyCode = "KeyN" CodeKeyO KeyCode = "KeyO" CodeKeyP KeyCode = "KeyP" CodeKeyQ KeyCode = "KeyQ" CodeKeyR KeyCode = "KeyR" CodeKeyS KeyCode = "KeyS" CodeKeyT KeyCode = "KeyT" CodeKeyU KeyCode = "KeyU" CodeKeyV KeyCode = "KeyV" CodeKeyW KeyCode = "KeyW" CodeKeyX KeyCode = "KeyX" CodeKeyY KeyCode = "KeyY" CodeKeyZ KeyCode = "KeyZ" CodeMinus KeyCode = "Minus" // -_ CodePeriod KeyCode = "Period" // .> CodeQuote KeyCode = "Quote" // '" CodeSemicolon KeyCode = "Semicolon" // ;: CodeSlash KeyCode = "Slash" // /?
// Functional keys of the alphanumeric section. CodeAltLeft KeyCode = "AltLeft" CodeAltRight KeyCode = "AltRight" // AltGr on many layouts CodeBackspace KeyCode = "Backspace" CodeCapsLock KeyCode = "CapsLock" CodeContextMenu KeyCode = "ContextMenu" CodeControlLeft KeyCode = "ControlLeft" CodeControlRight KeyCode = "ControlRight" CodeEnter KeyCode = "Enter" CodeMetaLeft KeyCode = "MetaLeft" // Windows, Command (⌘) or Super key CodeMetaRight KeyCode = "MetaRight" // Windows, Command (⌘) or Super key CodeShiftLeft KeyCode = "ShiftLeft" CodeShiftRight KeyCode = "ShiftRight" CodeSpace KeyCode = "Space" CodeTab KeyCode = "Tab" CodeConvert KeyCode = "Convert" // 変換 (Japanese) CodeKanaMode KeyCode = "KanaMode" // カタカナ/ひらがな/ローマ字 (Japanese) CodeLang1 KeyCode = "Lang1" // 한/영 (Korean), かな (Apple Japanese) CodeLang2 KeyCode = "Lang2" // 한자 (Korean), 英数 (Apple Japanese) CodeLang3 KeyCode = "Lang3" // カタカナ (Japanese) CodeLang4 KeyCode = "Lang4" // ひらがな (Japanese) CodeLang5 KeyCode = "Lang5" // 半角/全角 (Japanese) CodeNonConvert KeyCode = "NonConvert" // 無変換 (Japanese)
// Control pad. CodeDelete KeyCode = "Delete" CodeEnd KeyCode = "End" CodeHelp KeyCode = "Help" CodeHome KeyCode = "Home" CodeInsert KeyCode = "Insert" CodePageDown KeyCode = "PageDown" CodePageUp KeyCode = "PageUp"
// Arrow pad. CodeArrowDown KeyCode = "ArrowDown" CodeArrowLeft KeyCode = "ArrowLeft" CodeArrowRight KeyCode = "ArrowRight" CodeArrowUp KeyCode = "ArrowUp"
// Numpad section. CodeNumLock KeyCode = "NumLock" CodeNumpad0 KeyCode = "Numpad0" CodeNumpad1 KeyCode = "Numpad1" CodeNumpad2 KeyCode = "Numpad2" CodeNumpad3 KeyCode = "Numpad3" CodeNumpad4 KeyCode = "Numpad4" CodeNumpad5 KeyCode = "Numpad5" CodeNumpad6 KeyCode = "Numpad6" CodeNumpad7 KeyCode = "Numpad7" CodeNumpad8 KeyCode = "Numpad8" CodeNumpad9 KeyCode = "Numpad9" CodeNumpadAdd KeyCode = "NumpadAdd" CodeNumpadBackspace KeyCode = "NumpadBackspace" CodeNumpadClear KeyCode = "NumpadClear" CodeNumpadClearEntry KeyCode = "NumpadClearEntry" CodeNumpadComma KeyCode = "NumpadComma" CodeNumpadDecimal KeyCode = "NumpadDecimal" CodeNumpadDivide KeyCode = "NumpadDivide" CodeNumpadEnter KeyCode = "NumpadEnter" CodeNumpadEqual KeyCode = "NumpadEqual" CodeNumpadHash KeyCode = "NumpadHash" CodeNumpadMemoryAdd KeyCode = "NumpadMemoryAdd" CodeNumpadMemoryClear KeyCode = "NumpadMemoryClear" CodeNumpadMemoryRecall KeyCode = "NumpadMemoryRecall" CodeNumpadMemoryStore KeyCode = "NumpadMemoryStore" CodeNumpadMemorySubtract KeyCode = "NumpadMemorySubtract" CodeNumpadMultiply KeyCode = "NumpadMultiply" CodeNumpadParenLeft KeyCode = "NumpadParenLeft" CodeNumpadParenRight KeyCode = "NumpadParenRight" CodeNumpadStar KeyCode = "NumpadStar" CodeNumpadSubtract KeyCode = "NumpadSubtract"
// Function section. CodeEscape KeyCode = "Escape" CodeF1 KeyCode = "F1" CodeF2 KeyCode = "F2" CodeF3 KeyCode = "F3" CodeF4 KeyCode = "F4" CodeF5 KeyCode = "F5" CodeF6 KeyCode = "F6" CodeF7 KeyCode = "F7" CodeF8 KeyCode = "F8" CodeF9 KeyCode = "F9" CodeF10 KeyCode = "F10" CodeF11 KeyCode = "F11" CodeF12 KeyCode = "F12" CodeF13 KeyCode = "F13" CodeF14 KeyCode = "F14" CodeF15 KeyCode = "F15" CodeF16 KeyCode = "F16" CodeF17 KeyCode = "F17" CodeF18 KeyCode = "F18" CodeF19 KeyCode = "F19" CodeF20 KeyCode = "F20" CodeF21 KeyCode = "F21" CodeF22 KeyCode = "F22" CodeF23 KeyCode = "F23" CodeF24 KeyCode = "F24" CodeFn KeyCode = "Fn" CodeFnLock KeyCode = "FnLock" CodePrintScreen KeyCode = "PrintScreen" CodeScrollLock KeyCode = "ScrollLock" CodePause KeyCode = "Pause"
// Media keys. CodeBrowserBack KeyCode = "BrowserBack" CodeBrowserFavorites KeyCode = "BrowserFavorites" CodeBrowserForward KeyCode = "BrowserForward" CodeBrowserHome KeyCode = "BrowserHome" CodeBrowserRefresh KeyCode = "BrowserRefresh" CodeBrowserSearch KeyCode = "BrowserSearch" CodeBrowserStop KeyCode = "BrowserStop" CodeEject KeyCode = "Eject" CodeLaunchApp1 KeyCode = "LaunchApp1" // often "My Computer" CodeLaunchApp2 KeyCode = "LaunchApp2" // often "Calculator" CodeLaunchMail KeyCode = "LaunchMail" CodeMediaPlayPause KeyCode = "MediaPlayPause" CodeMediaSelect KeyCode = "MediaSelect" CodeMediaStop KeyCode = "MediaStop" CodeMediaTrackNext KeyCode = "MediaTrackNext" CodeMediaTrackPrevious KeyCode = "MediaTrackPrevious" CodePower KeyCode = "Power" CodeSleep KeyCode = "Sleep" CodeAudioVolumeDown KeyCode = "AudioVolumeDown" CodeAudioVolumeMute KeyCode = "AudioVolumeMute" CodeAudioVolumeUp KeyCode = "AudioVolumeUp" CodeWakeUp KeyCode = "WakeUp"
// Legacy, non-standard and special keys. CodeHyper KeyCode = "Hyper" CodeSuper KeyCode = "Super" CodeTurbo KeyCode = "Turbo" CodeAbort KeyCode = "Abort" CodeResume KeyCode = "Resume" CodeSuspend KeyCode = "Suspend" CodeAgain KeyCode = "Again" CodeCopy KeyCode = "Copy" CodeCut KeyCode = "Cut" CodeFind KeyCode = "Find" CodeOpen KeyCode = "Open" CodePaste KeyCode = "Paste" CodeProps KeyCode = "Props" CodeSelect KeyCode = "Select" CodeUndo KeyCode = "Undo" CodeHiragana KeyCode = "Hiragana" CodeKatakana KeyCode = "Katakana")Physical key codes: the values of KeyboardEvent.Code (W3C UI Events KeyboardEvent code values, https://www.w3.org/TR/uievents-code/), the position of the key whatever the layout: CodeKeyA is the key labeled A on a US keyboard (it types “q” on AZERTY). KeyCode is a string type: e.Code == “KeyS” and e.Code == tela.CodeKeyS mean the same.
type KeyLocation
Section titled “type KeyLocation”type KeyLocation = core.KeyLocationKeyLocation tells apart keys with the same meaning: the left and right Shift, Control, Alt and Meta keys, and the numeric keypad.
KeyLocation is an alias of core.KeyLocation, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type KeyLocation uint8const ( // KeyLocationStandard is every key not listed below. KeyLocationStandard KeyLocation = iota // KeyLocationLeft is the left Shift, Control, Alt or Meta key. KeyLocationLeft // KeyLocationRight is the right Shift, Control, Alt (AltGr) or Meta key. KeyLocationRight // KeyLocationNumpad is a key of the numeric keypad. KeyLocationNumpad)The key locations, with the DOM’s values.
func (KeyLocation) String
Section titled “func (KeyLocation) String”func (l KeyLocation) String() stringString returns “standard”, “left”, “right” or “numpad”.
type KeyName
Section titled “type KeyName”type KeyName = core.KeyValueKeyName is a logical key, the type of KeyboardEvent.Key: what the key means with the active layout and modifiers (a W3C KeyboardEvent key value). It is a named key, one of the Key constants (“Enter”, “Escape”, “ArrowLeft”, “Shift”), or the character the key types (“a”, “A”, “é”, “ “ for the space bar). Ctrl does not change it: Ctrl+S has Key “s”. Compare it with a constant or a string literal:
if e.Key == tela.KeyEnter || e.Key == "+" { ... }KeyName is an alias of core.KeyValue, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type KeyValue stringconst ( // KeyUnidentified is a key with neither a name nor a character. KeyUnidentified KeyName = "Unidentified"
// Modifier keys. AltGraph is AltGr (ISO_Level3_Shift); Meta is the // Windows, Command (⌘) or Super key, as browsers report it on every // OS. KeyAlt KeyName = "Alt" KeyAltGraph KeyName = "AltGraph" KeyCapsLock KeyName = "CapsLock" KeyControl KeyName = "Control" KeyFn KeyName = "Fn" KeyFnLock KeyName = "FnLock" KeyMeta KeyName = "Meta" KeyNumLock KeyName = "NumLock" KeyScrollLock KeyName = "ScrollLock" KeyShift KeyName = "Shift" KeySymbol KeyName = "Symbol" KeySymbolLock KeyName = "SymbolLock" KeyHyper KeyName = "Hyper" KeySuper KeyName = "Super"
// Whitespace keys (the space bar is the character " "). KeyEnter KeyName = "Enter" KeyTab KeyName = "Tab"
// Navigation keys. KeyArrowDown KeyName = "ArrowDown" KeyArrowLeft KeyName = "ArrowLeft" KeyArrowRight KeyName = "ArrowRight" KeyArrowUp KeyName = "ArrowUp" KeyEnd KeyName = "End" KeyHome KeyName = "Home" KeyPageDown KeyName = "PageDown" KeyPageUp KeyName = "PageUp"
// Editing keys. KeyBackspace KeyName = "Backspace" KeyClear KeyName = "Clear" KeyCopy KeyName = "Copy" KeyCrSel KeyName = "CrSel" KeyCut KeyName = "Cut" KeyDelete KeyName = "Delete" KeyEraseEof KeyName = "EraseEof" KeyExSel KeyName = "ExSel" KeyInsert KeyName = "Insert" KeyPaste KeyName = "Paste" KeyRedo KeyName = "Redo" KeyUndo KeyName = "Undo"
// UI keys. KeyAccept KeyName = "Accept" KeyAgain KeyName = "Again" KeyAttn KeyName = "Attn" KeyCancel KeyName = "Cancel" KeyContextMenu KeyName = "ContextMenu" KeyEscape KeyName = "Escape" KeyExecute KeyName = "Execute" KeyFind KeyName = "Find" KeyHelp KeyName = "Help" KeyPause KeyName = "Pause" KeyPlay KeyName = "Play" KeyProps KeyName = "Props" KeySelect KeyName = "Select" KeyZoomIn KeyName = "ZoomIn" KeyZoomOut KeyName = "ZoomOut"
// Device keys. KeyBrightnessDown KeyName = "BrightnessDown" KeyBrightnessUp KeyName = "BrightnessUp" KeyEject KeyName = "Eject" KeyLogOff KeyName = "LogOff" KeyPower KeyName = "Power" KeyPowerOff KeyName = "PowerOff" KeyPrintScreen KeyName = "PrintScreen" KeyHibernate KeyName = "Hibernate" KeyStandby KeyName = "Standby" KeyWakeUp KeyName = "WakeUp"
// IME and composition keys. Dead is a dead key (a pending accent or // other combining mark; the next key types the result). KeyAllCandidates KeyName = "AllCandidates" KeyAlphanumeric KeyName = "Alphanumeric" KeyCodeInput KeyName = "CodeInput" KeyCompose KeyName = "Compose" KeyConvert KeyName = "Convert" KeyDead KeyName = "Dead" KeyFinalMode KeyName = "FinalMode" KeyGroupFirst KeyName = "GroupFirst" KeyGroupLast KeyName = "GroupLast" KeyGroupNext KeyName = "GroupNext" KeyGroupPrevious KeyName = "GroupPrevious" KeyModeChange KeyName = "ModeChange" KeyNextCandidate KeyName = "NextCandidate" KeyNonConvert KeyName = "NonConvert" KeyPreviousCandidate KeyName = "PreviousCandidate" KeyProcess KeyName = "Process" KeySingleCandidate KeyName = "SingleCandidate" KeyHangulMode KeyName = "HangulMode" KeyHanjaMode KeyName = "HanjaMode" KeyJunjaMode KeyName = "JunjaMode" KeyEisu KeyName = "Eisu" KeyHankaku KeyName = "Hankaku" KeyHiragana KeyName = "Hiragana" KeyHiraganaKatakana KeyName = "HiraganaKatakana" KeyKanaMode KeyName = "KanaMode" KeyKanjiMode KeyName = "KanjiMode" KeyKatakana KeyName = "Katakana" KeyRomaji KeyName = "Romaji" KeyZenkaku KeyName = "Zenkaku" KeyZenkakuHankaku KeyName = "ZenkakuHankaku"
// General-purpose function keys. KeyF1 KeyName = "F1" KeyF2 KeyName = "F2" KeyF3 KeyName = "F3" KeyF4 KeyName = "F4" KeyF5 KeyName = "F5" KeyF6 KeyName = "F6" KeyF7 KeyName = "F7" KeyF8 KeyName = "F8" KeyF9 KeyName = "F9" KeyF10 KeyName = "F10" KeyF11 KeyName = "F11" KeyF12 KeyName = "F12" KeyF13 KeyName = "F13" KeyF14 KeyName = "F14" KeyF15 KeyName = "F15" KeyF16 KeyName = "F16" KeyF17 KeyName = "F17" KeyF18 KeyName = "F18" KeyF19 KeyName = "F19" KeyF20 KeyName = "F20" KeyF21 KeyName = "F21" KeyF22 KeyName = "F22" KeyF23 KeyName = "F23" KeyF24 KeyName = "F24"
// Multimedia keys. KeyClose KeyName = "Close" KeyMailForward KeyName = "MailForward" KeyMailReply KeyName = "MailReply" KeyMailSend KeyName = "MailSend" KeyMediaClose KeyName = "MediaClose" KeyMediaFastForward KeyName = "MediaFastForward" KeyMediaPause KeyName = "MediaPause" KeyMediaPlay KeyName = "MediaPlay" KeyMediaPlayPause KeyName = "MediaPlayPause" KeyMediaRecord KeyName = "MediaRecord" KeyMediaRewind KeyName = "MediaRewind" KeyMediaStop KeyName = "MediaStop" KeyMediaTrackNext KeyName = "MediaTrackNext" KeyMediaTrackPrevious KeyName = "MediaTrackPrevious" KeyNew KeyName = "New" KeyOpen KeyName = "Open" KeyPrint KeyName = "Print" KeySave KeyName = "Save" KeySpellCheck KeyName = "SpellCheck"
// Audio keys. KeyAudioVolumeDown KeyName = "AudioVolumeDown" KeyAudioVolumeUp KeyName = "AudioVolumeUp" KeyAudioVolumeMute KeyName = "AudioVolumeMute" KeyMicrophoneVolumeMute KeyName = "MicrophoneVolumeMute"
// Application launch keys. KeyLaunchApplication1 KeyName = "LaunchApplication1" KeyLaunchApplication2 KeyName = "LaunchApplication2" KeyLaunchCalendar KeyName = "LaunchCalendar" KeyLaunchMail KeyName = "LaunchMail" KeyLaunchMediaPlayer KeyName = "LaunchMediaPlayer" KeyLaunchMusicPlayer KeyName = "LaunchMusicPlayer" KeyLaunchPhone KeyName = "LaunchPhone" KeyLaunchScreenSaver KeyName = "LaunchScreenSaver" KeyLaunchSpreadsheet KeyName = "LaunchSpreadsheet" KeyLaunchWebBrowser KeyName = "LaunchWebBrowser" KeyLaunchWebCam KeyName = "LaunchWebCam" KeyLaunchWordProcessor KeyName = "LaunchWordProcessor"
// Browser keys. KeyBrowserBack KeyName = "BrowserBack" KeyBrowserFavorites KeyName = "BrowserFavorites" KeyBrowserForward KeyName = "BrowserForward" KeyBrowserHome KeyName = "BrowserHome" KeyBrowserRefresh KeyName = "BrowserRefresh" KeyBrowserSearch KeyName = "BrowserSearch" KeyBrowserStop KeyName = "BrowserStop")Named keys: the values of KeyboardEvent.Key that are not characters (W3C UI Events KeyboardEvent key values, https://www.w3.org/TR/uievents-key/). A key that produces a character has that character as its Key (“a”, “A”, “1”, “é”, and “ “ for the space bar), so compare with a string literal: e.Key == “z”. KeyName is a string type: e.Key == “Enter” and e.Key == tela.KeyEnter mean the same.
type KeyboardEvent
Section titled “type KeyboardEvent”type KeyboardEvent = core.KeyboardEventKeyboardEvent is passed to h.OnKeyDown and h.OnKeyUp: the logical Key, the physical Code, its Location, Repeat for a keydown generated while the key is held, and the modifiers held after the event (Shift, Ctrl, Alt, Meta; Meta is the Windows, Command or Super key). StopPropagation stops the bubbling; PreventDefault cancels the key’s default action (Tab’s focus move, the click of Enter or Space on a button, the text a key types into a text field). Typed text reaches text fields (h.Input, h.Textarea), which report it with h.OnChange.
OnKeyDown(func(e tela.KeyboardEvent) { switch { case e.Key == tela.KeyArrowDown: e.PreventDefault() setIndex.Update(func(i int) int { return min(i+1, n-1) }) case e.Ctrl && e.Key == "a": selectAll() }})KeyboardEvent is an alias of core.KeyboardEvent, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type KeyboardEvent struct { // Key is the logical key: "Enter", "Escape", "a", "A", " "... It // reflects Shift, AltGr and the lock keys, but not Ctrl: Ctrl+S has // Key "s" (Ctrl+Shift+S: "S"). Key KeyValue // Code is the physical key ("KeyS", "Enter", "ShiftLeft"), the same // whatever the layout and modifiers. Code CodeValue // Location tells left and right modifiers and the numeric keypad // apart. Location KeyLocation // Repeat marks a keydown generated by key repeat while the key is // held. Repeat bool // Modifier keys held after the event (the DOM's rule: the keydown of // Shift has Shift set, its keyup does not); Meta is the Windows, // Command or Super key. Shift, Ctrl, Alt, Meta bool // contains filtered or unexported fields}func (KeyboardEvent) DefaultPrevented
Section titled “func (KeyboardEvent) DefaultPrevented”func (e KeyboardEvent) DefaultPrevented() boolDefaultPrevented reports whether a handler called PreventDefault.
func (KeyboardEvent) PreventDefault
Section titled “func (KeyboardEvent) PreventDefault”func (e KeyboardEvent) PreventDefault()PreventDefault cancels the default action of the key: the focus move of Tab, the click of Enter or Space on a button.
func (KeyboardEvent) StopPropagation
Section titled “func (KeyboardEvent) StopPropagation”func (e KeyboardEvent) StopPropagation()StopPropagation stops the event from bubbling to the ancestors of the element whose handler runs. The other handlers of that element still run.
type MouseButton
Section titled “type MouseButton”type MouseButton = core.MouseButtonMouseButton is a mouse button, or the touch contact or pen tip that stands for the primary one.
MouseButton is an alias of core.MouseButton, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type MouseButton uint8const ( // MouseButtonNone is no button, as in a move or enter event. MouseButtonNone MouseButton = iota // MouseButtonLeft is the primary button: the left button (the right // one on a left-handed setup), a touch contact or a pen tip. MouseButtonLeft // MouseButtonRight is the secondary button (or a pen barrel button). MouseButtonRight // MouseButtonMiddle is the wheel button. MouseButtonMiddle // MouseButtonBack is the "back" side button. MouseButtonBack // MouseButtonForward is the "forward" side button. MouseButtonForward)The mouse buttons.
func (MouseButton) String
Section titled “func (MouseButton) String”func (b MouseButton) String() stringString returns the button name: “left”, “right”…
type MouseButtons
Section titled “type MouseButtons”type MouseButtons = core.MouseButtonsMouseButtons is a set of held buttons: e.Buttons.Has(tela.MouseButtonLeft).
MouseButtons is an alias of core.MouseButtons, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type MouseButtons uint8func (MouseButtons) Has
Section titled “func (MouseButtons) Has”func (s MouseButtons) Has(b MouseButton) boolHas reports whether b is in the set.
type MouseEvent
Section titled “type MouseEvent”type MouseEvent = core.MouseEventMouseEvent is passed to the mouse handlers (h.OnClick, h.OnMouseDown, h.OnContextMenu…). X and Y are window coordinates in logical pixels; LocalX and LocalY are relative to the border box of the element whose handler runs. ClickCount is 1 for a click, 2 for the second click of a double click. StopPropagation stops the bubbling; PreventDefault marks the event (on h.OnPointerDown it suppresses the press’s mouse events, not the click).
MouseEvent is an alias of core.MouseEvent, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type MouseEvent struct { // X and Y are the pointer position in logical pixels, relative to the // top-left corner of the window's content area. X, Y float32 // LocalX and LocalY are the position relative to the border box of // the element whose handler runs (the DOM's currentTarget), in its own // coordinates (its transforms and its ancestors' undone). LocalX, LocalY float32 // Button is the button that changed state for a press, release or // click; MouseButtonNone for moves, enter and leave. Button MouseButton // Buttons are the buttons held after the event. Buttons MouseButtons // Modifier keys held during the event; Meta is the Windows, Command // or Super key. Shift, Ctrl, Alt, Meta bool // ClickCount is the number of consecutive clicks (the DOM's detail): // 1 for a single click, 2 for the second click of a double click. // Presses and releases carry the count of the click they belong to; // moves, enter and leave carry 0. ClickCount int // contains filtered or unexported fields}func (MouseEvent) DefaultPrevented
Section titled “func (MouseEvent) DefaultPrevented”func (e MouseEvent) DefaultPrevented() boolDefaultPrevented reports whether a handler called PreventDefault.
func (MouseEvent) PreventDefault
Section titled “func (MouseEvent) PreventDefault”func (e MouseEvent) PreventDefault()PreventDefault cancels Tela’s default action for the event and marks it for the handlers that run after (DefaultPrevented). Cancelling OnPointerDown suppresses the mouse events of the press (OnMouseDown, OnMouseMove, OnMouseUp), but not OnClick, as in the DOM.
func (MouseEvent) StopPropagation
Section titled “func (MouseEvent) StopPropagation”func (e MouseEvent) StopPropagation()StopPropagation stops the event from bubbling to the ancestors of the element whose handler runs. The other handlers of that element still run.
type Node
Section titled “type Node”type Node = core.NodeNode is an immutable, cheap description of a piece of UI: an element (h.Div), a text (h.Text), a component or a fragment. Function components return one, and every build creates new ones; the persistent state lives elsewhere, keyed by position and key (ARCHITECTURE section 6).
The zero Node renders nothing. As a child of an element it keeps the positions of its siblings, so h.If(cond, node) does not remount the siblings when cond changes. A Node is a Component whose Build returns the node itself.
Node is an alias of core.Node, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type Node struct { // contains filtered or unexported fields}func C
Section titled “func C”func C(fn func() Node, key ...Child) NodeC returns a node that builds fn as a component with its own state: a component boundary (ARCHITECTURE section 7). Calling fn() directly instead runs it inside the caller’s build, so its hooks would take the caller’s slots: dev mode panics when a hook is called from a function that is neither the component being built (or a function literal inside it) nor a custom hook named UseXxx or useXxx, and says to wrap it.
Call C where the component is defined, in a public function over a private one, so that its users write Header() and not tela.C(header):
func Header() tela.Node { return tela.C(header) }
func header() tela.Node { ... }
Div(Header(), Body())The optional last argument is the component’s key, h.Key(id), for a component in a list: tela.C(row, Key(id)) is tela.WithKey(tela.C(row), id). Anything else but Key panics.
A C component builds whenever its parent builds, since fn may capture values that changed; use CP for automatic skipping. Only the very same node (one kept in a variable or a UseMemo) is not built again.
func CP
Section titled “func CP”func CP[P comparable](fn func(P) Node, props P, key ...Child) NodeCP returns a node that builds fn(props) as a component with its own state. When its parent builds again with props == to the previous ones, and neither its state nor a context it reads changed, the build is skipped (Jetpack Compose’s automatic skipping): free memoization.
type CardProps struct { Title string OnOpen tela.Callback[func(tela.MouseEvent)]}
func Card(p CardProps) tela.Node { return tela.CP(card, p) }
func card(p CardProps) tela.Node { ... }
Card(CardProps{Title: "Inbox", OnOpen: onOpen})Call CP where the component is defined, as above, so that its users never write it. Give CP a named function and pass everything it uses in its props: variables captured by a closure are not compared, so dev mode reports anonymous functions once per call site. Keep props comparable by passing Callback values instead of funcs, and IDs instead of slices or maps; a props value whose == panics counts as changed.
The optional last argument is the component’s key, h.Key(id), for the items of a list: tela.CP(row, RowProps{…}, Key(row.ID)) is tela.WithKey(tela.CP(row, RowProps{…}), row.ID). Anything else but Key panics; the key is not a prop of the component and is not compared with the props.
Example (key)
t := &exampleT{}defer t.close()var set tela.Setter[[]exampleRowProps]list := func() tela.Node { rows, s := tela.UseState([]exampleRowProps{{1, "Ada"}, {2, "Grace"}}) set = s nodes := make([]tela.Node, len(rows)) for i, r := range rows { // The key goes last: it is not a prop of the row. nodes[i] = tela.CP(exampleRow, r, Key(r.ID)) } return Div(Nodes(nodes))}app := telatest.Mount(t, tela.C(list))app.Click(telatest.ByText("Grace 0")) // Grace has been clicked onceset.Set([]exampleRowProps{{2, "Grace"}, {1, "Ada"}})fmt.Println(app.AriaSnapshot())// Output:// - button "Grace 1"// - button "Ada 0"func Memo
Section titled “func Memo”func Memo[P any](fn func(P) Node, props P, equal func(a, b P) bool, key ...Child) NodeMemo is CP for props that are not comparable, or that compare in another way: the build is skipped when equal(old, new) reports them equal. equal must be pure.
func Chart(p ChartProps) tela.Node { return tela.Memo(chart, p, func(a, b ChartProps) bool { return slices.Equal(a.Points, b.Points) })}Like CP, it takes an optional last argument, the key h.Key(id).
func WithKey
Section titled “func WithKey”func WithKey[K comparable](c Component, k K) NodeWithKey returns the node of c with the key k, whatever its kind: a node that cannot take the h.Key prop (a component or a fragment), or a struct component, WithKey(Card{…}, id), which it also turns into a Node (for h.Map and other places that want one). k is a comparable value, such as an ID: a slice or a map does not compile, and a nil interface, or one holding a value that cannot be compared, panics. A nil c or the zero Node give the zero Node; a Prop panics.
Map(cards, func(c CardData) tela.Node { return tela.WithKey(Card{Title: c.Title}, c.ID)})func (Node) Build
Section titled “func (Node) Build”func (n Node) Build() NodeBuild returns n itself: a Node is a Component that renders as itself.
func (Node) IsZero
Section titled “func (Node) IsZero”func (n Node) IsZero() boolIsZero reports whether n is the zero Node, which renders nothing.
func (Node) Key
Section titled “func (Node) Key”func (n Node) Key() (any, bool)Key returns the node’s key and whether it has one.
func (Node) String
Section titled “func (Node) String”func (n Node) String() stringtype Point
Section titled “type Point”type Point = core.PointPoint is a point in logical pixels: X to the right, Y down. It is one of the Animatable types, for a position that moves as a whole, such as a dragged card’s offset.
Point is an alias of core.Point, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type Point struct{ X, Y float32 }Example
t := &exampleT{}defer t.close()var pos *tela.Value[tela.Point]card := func() tela.Node { pos = tela.UseValue(tela.Point{}) return Div(Class("size-24 rounded-xl bg-white shadow"), Style(tela.TranslateFn(func() (float32, float32) { p := pos.Get(); return p.X, p.Y })), // Released: back to the origin on a bouncy spring. OnDragEnd(func(tela.DragEvent) { tela.Animate(pos, tela.Point{}, tela.Spring(tela.Bounce(0.4))) }), OnDrag(func(e tela.DragEvent) { pos.Set(tela.Point{X: e.OffsetX, Y: e.OffsetY}) }))}app := telatest.Mount(t, tela.C(card), telatest.NoSettle())// Called between frames (like from a goroutine), Animate starts at the// next frame: 50 ms later the tween has run for 33 ms of its 100.tela.Animate(pos, tela.Point{X: 40, Y: 30}, tela.Duration(100*time.Millisecond), tela.Ease("linear"))app.Advance(50 * time.Millisecond)fmt.Printf("%.0f %.0f\n", pos.Get().X, pos.Get().Y)// Output: 13 10type PointerEvent
Section titled “type PointerEvent”type PointerEvent = core.PointerEventPointerEvent is passed to the pointer handlers (h.OnPointerDown…, h.OnLongPress): the mouse fields plus the pointer’s Kind, PointerID, Pressure and IsPrimary.
PointerEvent is an alias of core.PointerEvent, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type PointerEvent struct { // X and Y are the position in the window, LocalX and LocalY relative // to the border box of the element whose handler runs (see // MouseEvent). X, Y, LocalX, LocalY float32 // Button is the button that changed state (MouseButtonNone for moves, // enter and leave); Buttons the buttons held after the event. Button MouseButton Buttons MouseButtons // Modifier keys held during the event. Shift, Ctrl, Alt, Meta bool // Kind is the device: mouse, touch or pen. Kind PointerKind // PointerID identifies the pointer among those present: the mouse is // always 1; each touch contact has its own. PointerID int // Pressure is the normalized pressure, 0 to 1: 0.5 while a button is // held and 0 otherwise when the device does not report it (the DOM's // rule; no backend reports pressure yet). Pressure float32 // IsPrimary reports the primary pointer of its kind: the mouse, the // first touch contact, the pen. Mouse events are fired for it only. IsPrimary bool // contains filtered or unexported fields}func (PointerEvent) DefaultPrevented
Section titled “func (PointerEvent) DefaultPrevented”func (e PointerEvent) DefaultPrevented() boolDefaultPrevented reports whether a handler called PreventDefault.
func (PointerEvent) PreventDefault
Section titled “func (PointerEvent) PreventDefault”func (e PointerEvent) PreventDefault()PreventDefault cancels the default action (see MouseEvent).
func (PointerEvent) StopPropagation
Section titled “func (PointerEvent) StopPropagation”func (e PointerEvent) StopPropagation()StopPropagation stops the event from bubbling (see MouseEvent).
type PointerKind
Section titled “type PointerKind”type PointerKind = core.PointerKindPointerKind is the device behind a pointer.
PointerKind is an alias of core.PointerKind, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type PointerKind uint8const ( PointerMouse PointerKind = iota // a mouse or touchpad cursor PointerTouch // a finger on a touchscreen PointerPen // a stylus)The pointer kinds.
func (PointerKind) String
Section titled “func (PointerKind) String”func (k PointerKind) String() stringString returns “mouse”, “touch” or “pen”.
type Preview
Section titled “type Preview”type Preview struct { // Root is the screen. It must not be nil. Root Component // Wrap, when not nil, receives the node of Root and returns what is // mounted instead, normally Root inside the Provider of every context // it reads. It runs each time the preview builds and may not use // hooks: put state in a component. Wrap func(Node) Node}Preview is one screen of a package for tela snapshot, tela inspect and Previews: the component to show, and optionally a wrapper that supplies what the screen reads from context.
Root is a Component: a node such as Settings(), a function that returns tela.C(settings), or a struct component value. The local state of a preview is seeded through the fields of a struct component, with no global:
type Main struct{ InitialTab string }
func (m Main) Build() tela.Node { tab, setTab := tela.UseState(m.InitialTab) ...}
var Previews = tela.Previews{ "open": {Root: Main{InitialTab: "open"}},}State that comes from a context is seeded with Wrap, which receives the root as a node and returns it inside the providers the screen needs:
var Previews = tela.Previews{ "mocked": { Root: Main{}, Wrap: func(n tela.Node) tela.Node { return AppState.Provider(mockState, n) }, },}A Preview is itself a Component that builds Wrap(Root): the CLI mounts exactly that, and a test mounts a preview the way the CLI does with telatest.Mount(t, Previews[“mocked”]).
Example
// A Preview is a Component: mount it as `tela snapshot` does.for _, name := range inboxPreviews.Names() { yaml, _ := telatest.AriaSnapshot(inboxPreviews[name]) fmt.Printf("%s: %s\n", name, strings.TrimPrefix(yaml, "- text: "))}// Output:// closed: guest sees the closed tab// mocked: Ana sees the open tab// open: guest sees the open tabfunc (Preview) Build
Section titled “func (Preview) Build”func (p Preview) Build() NodeBuild returns the node the preview mounts: Root, or Wrap(Root) when Wrap is set. It panics when Root is nil.
type Previews
Section titled “type Previews”type Previews map[string]PreviewPreviews are the named screens of a package, for tela snapshot and tela inspect (ARCHITECTURE section 17). Define one as a package-level variable called Previews:
var Previews = tela.Previews{ "Login": {Root: LoginScreen()}, "Settings": {Root: Settings{InitialTab: "account"}},}Each Root is a component, so it may use hooks. The CLI renders the preview selected with –preview NAME; without the flag it renders the first name in byte order (see Previews.Names), so a name such as “1 Login” can pick the default. A package with a single screen can define func Preview() tela.Node (or tela.Component) instead. See Preview to start a screen in a given state.
Example
login := func() tela.Node { return core.Text("Login") }settings := func() tela.Node { return core.Text("Settings") }
previews := tela.Previews{ "Settings": {Root: tela.C(settings)}, "Login": {Root: tela.C(login)},}// `tela snapshot` renders the first name unless --preview says otherwise.fmt.Println(previews.Names())// Output: [Login Settings]func (Previews) Names
Section titled “func (Previews) Names”func (p Previews) Names() []stringNames returns the preview names in the order the CLI uses: sorted by bytes. The first is the default preview.
type Prop
Section titled “type Prop”type Prop = core.PropProp is a property of an element: classes, typed style, key, event handlers, an image source. Built by the functions of package h. A Prop is a Child (and, by its method set, a Component, although it renders nothing: dev mode reports one held by a field of type Component).
Prop is an alias of core.Prop, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type Prop struct { // contains filtered or unexported fields}func MergeProps
Section titled “func MergeProps”func MergeProps(props ...Child) PropMergeProps returns one Prop that applies props in order, for a place that takes a single one: kit’s Props field of type Child, or a hook’s result next to your own props. Event handlers accumulate (every handler of an event runs, in order); the other props are set by the last one that sets them, as when they are given one after the other to an element. Nil and the zero Prop are skipped.
It takes only props, and style props such as tela.Width. A Node or another Component is not a prop and cannot be merged into one: dev mode panics, naming the argument, and otherwise it is ignored.
kit.Button{Children: Text("Save"), Props: tela.MergeProps( TestID("save"), OnMouseEnter(prefetch), AriaLabel("Save the draft"))}Example
Several props where one is taken: a kit component’s Props field.
t := &exampleT{}defer t.close()page := func() tela.Node { return Div( Button(Class("rounded border px-3"), Text("Save"), tela.MergeProps( TestID("save"), AriaLabel("Save the draft"), OnClick(func() { fmt.Println("clicked") }), OnClick(func() { fmt.Println("and again") }), )))}app := telatest.Mount(t, tela.C(page))app.Click(telatest.ByTestID("save"))app.ExpectRole("button", "Save the draft")// Output:// clicked// and againfunc (Prop) Build
Section titled “func (Prop) Build”func (p Prop) Build() NodeBuild returns a node that holds p: given to an element (or to a Fragment, a Provider or a Presence, which take Key only) it applies like p itself; mounted on its own it panics, since a prop renders nothing. It is what makes Prop a Child.
type Rect
Section titled “type Rect”type Rect = core.RectRect is a rectangle in logical pixels: the position of its top-left corner (X, Y) and its size (Width, Height). Right, Bottom and Contains derive from them. It is what ElementRef.Bounds and UseBounds return, in window coordinates (the window’s top-left corner is 0, 0), like the DOM’s DOMRect.
Rect is an alias of core.Rect, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type Rect struct{ X, Y, Width, Height float32 }func (Rect) Bottom
Section titled “func (Rect) Bottom”func (r Rect) Bottom() float32Bottom returns the y of the bottom edge.
func (Rect) Contains
Section titled “func (Rect) Contains”func (r Rect) Contains(x, y float32) boolContains reports whether the point (x, y) is inside r (the right and bottom edges are outside).
func (Rect) Right
Section titled “func (Rect) Right”func (r Rect) Right() float32Right returns the x of the right edge.
type Ref
Section titled “type Ref”type Ref[T any] = core.Ref[T]Ref is a mutable box returned by UseRef: the same pointer on every build. Changing Current does not rebuild.
Ref is an alias of core.Ref, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type Ref[T any] struct { Current T}func UseRef
Section titled “func UseRef”func UseRef[T any](initial T) *Ref[T]UseRef returns the Ref of this hook slot, a box whose Current field persists across builds; the first build sets it to initial. Changing Current does not rebuild: use it for values that rendering does not show, such as a timer or the previous value of a prop.
renders := tela.UseRef(0)renders.Current++type SchemeColor
Section titled “type SchemeColor”type SchemeColor = core.SchemeColorSchemeColor is the value of a theme color in the light and the dark color scheme.
tela.SchemeColor{Light: tela.Hex("#fafafa"), Dark: tela.Hex("#0a0a0a")}SchemeColor is an alias of core.SchemeColor, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type SchemeColor = style.SchemeColortype ScrollAlign
Section titled “type ScrollAlign”type ScrollAlign = core.ScrollAlignScrollAlign is where ElementRef.ScrollToIndex puts an item of an h.VirtualList in its viewport (TanStack Virtual’s align).
ScrollAlign is an alias of core.ScrollAlign, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type ScrollAlign uint8const ( // AlignAuto scrolls as little as possible: nothing when the item is // fully visible, else to align its end (when it reaches past the // bottom) or its start. AlignAuto ScrollAlign = iota // AlignStart puts the item's top at the top of the scrollport. AlignStart // AlignCenter centers the item in the scrollport. AlignCenter // AlignEnd puts the item's bottom at the bottom of the scrollport. AlignEnd)func (ScrollAlign) String
Section titled “func (ScrollAlign) String”func (a ScrollAlign) String() stringtype ScrollEvent
Section titled “type ScrollEvent”type ScrollEvent = core.ScrollEventScrollEvent is passed to h.OnScroll after an element’s scroll offsets changed, by the user or by code (the DOM’s scroll event: at most once per frame, on the scrolling element only; it does not bubble). The fields are the DOM’s scroll properties in logical pixels: ScrollLeft and ScrollTop (the offsets), ScrollWidth and ScrollHeight (the content size), ClientWidth and ClientHeight (the visible size).
Div(Class("h-96 overflow-y-auto"), OnScroll(func(e tela.ScrollEvent) { if e.ScrollTop+e.ClientHeight >= e.ScrollHeight-200 { loadMore() }}), rows)ScrollEvent is an alias of core.ScrollEvent, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type ScrollEvent struct { // ScrollLeft and ScrollTop are the scroll offsets: how far the // content is scrolled from its start. In a right-to-left container // (Dir("rtl")) the start is the right: ScrollLeft is 0 there and // negative toward the left, as in the DOM. ScrollLeft, ScrollTop float32 // ScrollWidth and ScrollHeight are the size of the scrollable content // (at least the client size); the largest offsets are ScrollWidth - // ClientWidth and ScrollHeight - ClientHeight. ScrollWidth, ScrollHeight float32 // ClientWidth and ClientHeight are the size of the visible area: the // padding box without the scrollbars' gutters. ClientWidth, ClientHeight float32 // contains filtered or unexported fields}func (ScrollEvent) DefaultPrevented
Section titled “func (ScrollEvent) DefaultPrevented”func (e ScrollEvent) DefaultPrevented() boolDefaultPrevented reports whether a handler called PreventDefault.
func (ScrollEvent) PreventDefault
Section titled “func (ScrollEvent) PreventDefault”func (e ScrollEvent) PreventDefault()PreventDefault marks the event; the scroll already happened.
func (ScrollEvent) StopPropagation
Section titled “func (ScrollEvent) StopPropagation”func (e ScrollEvent) StopPropagation()StopPropagation does nothing: scroll events do not bubble. It exists for symmetry with the other events.
type SelectEvent
Section titled “type SelectEvent”type SelectEvent = core.SelectEventSelectEvent is passed to h.OnSelect when the user selects text in a text field or code changes its selection: Start and End are the selection in UTF-8 byte offsets of the value. It bubbles.
SelectEvent is an alias of core.SelectEvent, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type SelectEvent struct { Start, End int // contains filtered or unexported fields}func (SelectEvent) DefaultPrevented
Section titled “func (SelectEvent) DefaultPrevented”func (e SelectEvent) DefaultPrevented() boolDefaultPrevented reports whether a handler called PreventDefault.
func (SelectEvent) PreventDefault
Section titled “func (SelectEvent) PreventDefault”func (e SelectEvent) PreventDefault()PreventDefault marks the event; the selection already changed.
func (SelectEvent) StopPropagation
Section titled “func (SelectEvent) StopPropagation”func (e SelectEvent) StopPropagation()StopPropagation stops the event from bubbling (see MouseEvent).
type Setter
Section titled “type Setter”type Setter[T any] = core.Setter[T]Setter sets the state of one UseState slot. It is a small comparable value, the same on every build of the slot, so it can be stored, passed to goroutines and put in props compared by CP. Its methods are safe from any goroutine: they queue the update and wake the UI thread, which applies the queued updates in order before the next build. Updates to a component that has been unmounted are dropped. The zero Setter is not tied to any state; its methods panic, and IsZero reports it (a Setter field left unset, or one read from a context default without a Provider).
setCount.Set(0)setCount.Update(func(n int) int { return n + 1 })Set(v) replaces the state; Update(f) computes it from the state left by the previous queued update, so two queued Update(inc) add 2. f runs on the UI thread and must be pure. For comparable types, a new state == to the current one does not rebuild.
Setter is an alias of core.Setter, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type Setter[T any] struct { // contains filtered or unexported fields}func UseState
Section titled “func UseState”func UseState[T any](initial T) (T, Setter[T])UseState returns the state of this hook slot and its Setter (ARCHITECTURE section 7). The first build stores initial; later builds return the latest value set. Setting a different value rebuilds the component in the next frame.
func Counter() tela.Node { count, setCount := tela.UseState(0) return Button(OnClick(func(tela.MouseEvent) { setCount.Set(count + 1) }), Textf("Clicked %d times", count))}Use setCount.Update(func(n int) int { return n + 1 }) when the new state depends on the old one and several updates may be queued before the next build (from goroutines, or several events in one frame).
Hooks follow React’s rules: call them at the top level of a component function, in the same order on every build, never inside conditions or loops. UseState panics when called outside a component build or when the call order changed since the previous build.
func (Setter) IsZero
Section titled “func (Setter) IsZero”func (st Setter[T]) IsZero() boolIsZero reports whether st is the zero Setter, which is not tied to any state: its methods panic. A Setter left unset in a struct, or read from a context default without a Provider, is zero.
func (Setter) Set
Section titled “func (Setter) Set”func (st Setter[T]) Set(v T)Set queues setting the state to v. For comparable types, a value == to the state when the update applies does not rebuild.
func (Setter) Update
Section titled “func (Setter) Update”func (st Setter[T]) Update(f func(T) T)Update queues f, which receives the state left by the previous queued update and returns the new one: two queued Update(inc) add 2. f runs on the UI thread when the update applies, and must be pure (no side effects: it may run later than the call).
type Shadow
Section titled “type Shadow”type Shadow = style.ShadowShadow is one box shadow layer: OffsetX, OffsetY, Blur and Spread in logical pixels, its Color, and Inset for an inner shadow.
Shadow is an alias of style.Shadow, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type Shadow struct { OffsetX float32 OffsetY float32 Blur float32 Spread float32 Color gfx.Color Inset bool}type Size
Section titled “type Size”type Size = core.SizeSize is a width and a height in logical pixels. It is one of the Animatable types.
Size is an alias of core.Size, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type Size struct{ Width, Height float32 }Example
t := &exampleT{}defer t.close()var size *tela.Value[tela.Size]app := telatest.Mount(t, tela.C(func() tela.Node { size = tela.UseSpring(tela.Size{Width: 200, Height: 120}, tela.Initial(tela.Size{Width: 100, Height: 40})) return Div(Class("rounded-lg bg-sky-500"), Style( tela.WidthFn(func() float32 { return size.Get().Width }), tela.HeightFn(func() float32 { return size.Get().Height })))}))// Mount settles: the spring from the initial size to the target ended.wBox := app.Bounds(telatest.ByClass("bg-sky-500"))w, h := wBox.Width, wBox.Heightfmt.Println(w, h)// Output: 200 120type StopHandler
Section titled “type StopHandler”type StopHandler func()StopHandler is the handler tela.StopPropagation returns. It is a named func() type, so every h.On… handler prop accepts it: the prop calls e.StopPropagation() on the event and then the function.
func StopPropagation
Section titled “func StopPropagation”func StopPropagation(f func()) StopHandlerStopPropagation turns f into a handler that stops the event from bubbling to the ancestors’ handlers and then calls f: the one-line form of a handler that begins with e.StopPropagation(). It works in every handler prop (OnClick, OnKeyDown, OnPointerDown, OnChange…), whatever the event type, and f does not take the event:
Button(OnClick(tela.StopPropagation(ctrl.Remove)), Text("Delete")) // the row's OnClick does not runDiv(OnKeyDown(tela.StopPropagation(close)))A handler that needs the event, to stop propagation only for some events, calls e.StopPropagation() itself. The press hook of the aria package (aria.UsePress) stops propagation by default, as React Aria does. StopPropagation(nil) panics.
type StyleProp
Section titled “type StyleProp”type StyleProp = core.StylePropStyleProp is one typed style declaration, built by the functions below and passed to h.Style. Typed props apply after the element’s classes, so they win over a class that sets the same property; use them for values that come from code (a measured width, a color from state). Lengths are logical pixels.
A StyleProp is a Child: besides h.Style(tela.Width(10)), an element takes it directly, Div(tela.Width(10), tela.Bg(c)), which is the same (and h.If(cond, tela.Opacity(0.5)) works). Box and WH return a StyleProp of several declarations.
StyleProp is an alias of core.StyleProp, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type StyleProp struct { // contains filtered or unexported fields}Example
t := &exampleT{}defer t.close()// A StyleProp is a child: no Style(...) around it, and If takes it.selected := trueapp := telatest.Mount(t, Div(TestID("swatch"), Class("size-8"), tela.Bg(tela.Hex("#336699")), If(selected, tela.Opacity(0.5))), telatest.Size(100, 100))fmt.Println(app.Bounds(telatest.ByTestID("swatch")).Width, app.PixelAt(16, 16))// Output: 32 {153 178 204 255}func BackgroundGradient
Section titled “func BackgroundGradient”func BackgroundGradient(g Gradient) StylePropBackgroundGradient sets a gradient as the background image, over the background color.
func Bg
Section titled “func Bg”func Bg(c Color) StylePropBg sets the background color.
func BgFn
Section titled “func BgFn”func BgFn(fn func() Color) StylePropBgFn defers Bg to the paint phase: the element’s background color is fn’s, and a change of the Values fn reads repaints the element without building, computing styles or laying out. Like the other Fn props it wins over the background classes, and over their transitions. With a UseSpring or Animate of a Color it animates a background without rebuilding:
bg := tela.UseSpring(target) // target is a tela.ColorDiv(Class("rounded-lg p-4"), Style(tela.BgFn(bg.Get)))Example
t := &exampleT{}defer t.close()var bg *tela.Value[tela.Color]app := telatest.Mount(t, tela.C(func() tela.Node { bg = tela.UseValue(tela.Hex("#ffffff")) return Div(Class("size-10"), Style(tela.BgFn(bg.Get)))}), telatest.Size(40, 40))before := app.Stats()bg.Set(tela.Hex("#4f46e5"))after := app.Stats() // settles: the frame that shows the change// The change repainted the box: no build, style or layout.fmt.Println(app.Screenshot().RGBAAt(5, 5), after.Builds-before.Builds, after.Styles-before.Styles, after.Layouts-before.Layouts)// Output: {79 70 229 255} 0 0 0func BgImage
Section titled “func BgImage”func BgImage(img image.Image) StylePropBgImage sets a decoded image as the background image, over the background color. The background classes apply to it as to a bg-[url(…)] image: bg-cover, bg-contain, bg-center, bg-no-repeat, bg-origin-*, bg-clip-* and the others. Each image.Image value is converted once and cached (the cache keeps the most recently used images, up to 256 MiB of pixels), so pass the same value on every build and do not modify its pixels afterwards: give a new image instead. For images stored as files, register them with Assets and use a class.
Example
// A decoded image, such as one from image.Decode or generated in// code. Pass the same value on every build: it is converted once.photo := image.NewRGBA(image.Rect(0, 0, 4, 4))for i := range 16 { photo.Set(i%4, i/4, color.RGBA{B: 255, A: 255})}
// With package h: Div(Class("size-8 bg-cover bg-center"), Style(tela.BgImage(photo))).card := core.Primitive(style.KindDiv, core.Class("size-8 bg-cover bg-center"), tela.BgImage(photo))_, img := core.Render(card, core.RenderOptions{Width: 32, Height: 32})fmt.Println(img.RGBAAt(16, 16))// Output: {0 0 255 255}func BorderColor
Section titled “func BorderColor”func BorderColor(c Color) StylePropBorderColor sets the color of the four borders.
func BorderWidth
Section titled “func BorderWidth”func BorderWidth(px float32) StylePropBorderWidth sets the width of the four borders in pixels.
func Bottom
Section titled “func Bottom”func Bottom(px float32) StylePropBottom sets the bottom inset of a positioned element in pixels.
func Box
Section titled “func Box”func Box(x, y, w, h float32) StylePropBox places and sizes a positioned element in pixels: its Left and Top insets and its Width and Height, in one StyleProp (the typed form of “left-[x] top-[y] w-[w] h-h”; the element needs a position class such as absolute or relative, and a rectangle from ElementRef.Bounds or UseBounds fits it).
Div(Class("absolute rounded-md ring-2 ring-indigo-500"), tela.Box(r.X, r.Y, r.Width, r.Height))Example
t := &exampleT{}defer t.close()app := telatest.Mount(t, Div(Class("relative h-40 w-60"), Div(TestID("marker"), Class("absolute rounded ring-2 ring-indigo-500"), tela.Box(20, 10, 80, 30))), telatest.Size(240, 160))fmt.Println(app.Bounds(telatest.ByTestID("marker")))// Output: {20 10 80 30}func BoxShadow
Section titled “func BoxShadow”func BoxShadow(layers ...Shadow) StylePropBoxShadow sets the box shadows, replacing those of shadow-* classes.
func FontSize
Section titled “func FontSize”func FontSize(px float32) StylePropFontSize sets the font size in pixels.
func FontWeight
Section titled “func FontWeight”func FontWeight(w float32) StylePropFontWeight sets the font weight, from 100 to 900.
func Gap
Section titled “func Gap”func Gap(px float32) StylePropGap sets the row and column gap of a flex container in pixels.
func Height
Section titled “func Height”func Height(px float32) StylePropHeight sets the height in pixels.
func HeightFn
Section titled “func HeightFn”func HeightFn(fn func() float32) StylePropHeightFn defers Height, in pixels, to the layout phase: a change of the Values fn reads lays the element out again, without building it.
func Left
Section titled “func Left”func Left(px float32) StylePropLeft sets the left inset of a positioned element in pixels.
func Margin
Section titled “func Margin”func Margin(px float32) StylePropMargin sets the margin of the four sides in pixels.
func MaxHeight
Section titled “func MaxHeight”func MaxHeight(px float32) StylePropMaxHeight sets the maximum height in pixels.
func MaxWidth
Section titled “func MaxWidth”func MaxWidth(px float32) StylePropMaxWidth sets the maximum width in pixels.
func MinHeight
Section titled “func MinHeight”func MinHeight(px float32) StylePropMinHeight sets the minimum height in pixels.
func MinWidth
Section titled “func MinWidth”func MinWidth(px float32) StylePropMinWidth sets the minimum width in pixels.
func Opacity
Section titled “func Opacity”func Opacity(v float32) StylePropOpacity sets the opacity from 0 (transparent) to 1.
func OpacityFn
Section titled “func OpacityFn”func OpacityFn(fn func() float32) StylePropOpacityFn defers Opacity to the paint phase: a change of the Values fn reads repaints the element, without layout.
func Padding
Section titled “func Padding”func Padding(px float32) StylePropPadding sets the padding of the four sides in pixels.
func PaddingXY
Section titled “func PaddingXY”func PaddingXY(x, y float32) StylePropPaddingXY sets the horizontal and vertical padding in pixels.
func Radius
Section titled “func Radius”func Radius(px float32) StylePropRadius sets the radius of the four corners in pixels.
func Right
Section titled “func Right”func Right(px float32) StylePropRight sets the right inset of a positioned element in pixels.
func Rotate
Section titled “func Rotate”func Rotate(deg float32) StylePropRotate rotates the element by deg degrees, clockwise.
func Scale
Section titled “func Scale”func Scale(x, y float32) StylePropScale scales the element by x and y (1 is no change) without affecting layout.
func TextColor
Section titled “func TextColor”func TextColor(c Color) StylePropTextColor sets the text color, which the element’s descendants inherit.
func TextColorFn
Section titled “func TextColorFn”func TextColorFn(fn func() Color) StylePropTextColorFn defers TextColor to the paint phase: a change of the Values fn reads repaints the text without building, computing styles or laying out. The element’s text takes fn’s color, and so does the text of its descendants that inherits the element’s color: those whose classes (and the classes of the elements between) set no text color of their own, as CSS inheritance would give it. Underlines and other decorations without a color of their own follow the text. Colors that the classes derive from the text color when the style is computed (currentColor borders, outlines, ring colors) and the text of h.Input and h.Textarea keep the color their classes give. It wins over the text color classes and their transitions.
color := tela.UseTween(target, tela.Duration(200*time.Millisecond)) // a tela.ColorP(Style(tela.TextColorFn(color.Get)), Text("Status: "), Strong(Text("online")))Example
t := &exampleT{}defer t.close()var c *tela.Value[tela.Color]app := telatest.Mount(t, tela.C(func() tela.Node { c = tela.UseValue(tela.Hex("#0f172a")) // The Strong inherits the paragraph's color, so it follows the Fn // too; the Span has a color of its own. return P(Style(tela.TextColorFn(c.Get)), Text("Status: "), Strong(Text("online")), Span(Class("text-slate-400"), Text(" (auto)")))}))before := app.Stats()c.Set(tela.Hex("#16a34a"))after := app.Stats()// Builds, styles, layouts and paints of the change.fmt.Println(after.Builds-before.Builds, after.Styles-before.Styles, after.Layouts-before.Layouts, after.Paints-before.Paints)// Output: 0 0 0 1func Top
Section titled “func Top”func Top(px float32) StylePropTop sets the top inset of a positioned element in pixels.
func Translate
Section titled “func Translate”func Translate(x, y float32) StylePropTranslate moves the element by x and y pixels without affecting layout.
func TranslateFn
Section titled “func TranslateFn”func TranslateFn(fn func() (x, y float32)) StylePropTranslateFn defers Translate to the paint phase: a change of the Values fn reads repaints the element, without layout.
Style(tela.TranslateFn(func() (x, y float32) { return float32(pos.Get()), 0 }))func WH
Section titled “func WH”func WH(w, h float32) StylePropWH sets the width and the height in pixels: WH(w, h) is Width(w) and Height(h) in one StyleProp. It is named for its two arguments because Size is the type of the animatable sizes.
Div(tela.WH(240, 160), Class("rounded-xl bg-white"))Example
t := &exampleT{}defer t.close()app := telatest.Mount(t, Div(TestID("card"), Class("rounded-xl bg-white"), tela.WH(240, 160)), telatest.Size(300, 200))fmt.Println(app.Bounds(telatest.ByTestID("card")))// Output: {0 0 240 160}func Width
Section titled “func Width”func Width(px float32) StylePropWidth sets the width in pixels.
func WidthFn
Section titled “func WidthFn”func WidthFn(fn func() float32) StylePropWidthFn defers Width, in pixels, to the layout phase: a change of the Values fn reads lays the element out again, without building it.
func ZIndex
Section titled “func ZIndex”func ZIndex(z int) StylePropZIndex sets an explicit z-index (it applies to positioned elements and flex items).
func (StyleProp) Build
Section titled “func (StyleProp) Build”func (p StyleProp) Build() NodeBuild returns the node of Style(p): given to an element it applies the typed style props after the classes, like h.Style(p); mounted on its own it panics, since a prop renders nothing.
func (StyleProp) Ops
Section titled “func (StyleProp) Ops”func (p StyleProp) Ops() []style.OpOps returns the ops of p, in order. The slice must not be modified.
type SubmitEvent
Section titled “type SubmitEvent”type SubmitEvent = core.SubmitEventSubmitEvent is passed to h.OnSubmit when a h.Form is submitted: Enter in a single-line field of the form, or a click on a submit button inside it. Tela does not navigate; PreventDefault exists for familiarity.
Form(OnSubmit(func(e tela.SubmitEvent) { e.PreventDefault() login(email, password)}), ...)SubmitEvent is an alias of core.SubmitEvent, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type SubmitEvent struct { // contains filtered or unexported fields}func (SubmitEvent) DefaultPrevented
Section titled “func (SubmitEvent) DefaultPrevented”func (e SubmitEvent) DefaultPrevented() boolDefaultPrevented reports whether a handler called PreventDefault.
func (SubmitEvent) PreventDefault
Section titled “func (SubmitEvent) PreventDefault”func (e SubmitEvent) PreventDefault()PreventDefault marks the event.
func (SubmitEvent) StopPropagation
Section titled “func (SubmitEvent) StopPropagation”func (e SubmitEvent) StopPropagation()StopPropagation stops the event from bubbling (see MouseEvent).
type Theme
Section titled “type Theme”type Theme struct { // Colors maps token names to their values in the light and the dark // scheme. Colors map[string]SchemeColor // Radius is the base radius in logical pixels, shadcn/ui's --radius: // rounded-lg is Radius, rounded-sm 0.6 x, rounded-md 0.8 x, // rounded-xl 1.4 x, rounded-2xl 1.8 x, rounded-3xl 2.2 x and // rounded-4xl 2.6 x (shadcn/ui v4's theme). 0 keeps Tailwind's radius // scale, which DefaultTheme does so that existing pages do not change; // set 10 for shadcn/ui's look. Radius float32 // FontSans and FontMono are font family names for font-sans (also // the default text font) and font-mono (code, kbd, pre, samp); the // embedded Inter and JetBrains Mono stay as fallbacks. "" keeps the // defaults. FontSans, FontMono string}Theme holds an app’s design tokens: semantic colors with a light and a dark value, the base radius and the font families. Classes name the colors like palette colors, with every color utility, opacity modifier, variant and transition: bg-primary, text-muted-foreground, border-border, ring-ring/50, hover:bg-primary/90, from-chart-1. A token takes the value of the color scheme of the element that uses it (App.ColorScheme, SetColorScheme, or the Scheme prop of an ancestor, h.Scheme), so one class serves both schemes, without dark: pairs.
The token names are shadcn/ui’s (v4): background, foreground, card, card-foreground, popover, popover-foreground, primary, primary-foreground, secondary, secondary-foreground, muted, muted-foreground, accent, accent-foreground, destructive, border, input, ring and chart-1 to chart-5. DefaultTheme holds shadcn/ui’s neutral values; start from it and change what you need:
theme := tela.DefaultTheme()theme.Colors["primary"] = tela.SchemeColor{Light: tela.OKLCH(0.55, 0.2, 264), Dark: tela.OKLCH(0.7, 0.16, 264)}theme.Colors["brand"] = tela.SchemeColor{Light: tela.Hex("#7c3aed"), Dark: tela.Hex("#a78bfa")} // bg-brandtheme.Radius = 10 // shadcn/ui's 0.625remtela.Main(tela.App{Title: "Notes", Root: Notes(), Theme: &theme, RootClass: "bg-background text-foreground"})A token missing from Colors keeps its value in DefaultTheme, so the shadcn/ui tokens always resolve. A token name is lowercase letters, digits and dashes, and cannot be a palette color (“red-500”, “white”) or transparent, current or inherit; Run panics otherwise. Tokens cannot be used inside arbitrary values (bg-[linear-gradient(…)]): use the utilities (from-primary, shadow-primary).
func DefaultTheme
Section titled “func DefaultTheme”func DefaultTheme() ThemeDefaultTheme returns the default theme: shadcn/ui’s neutral colors (v4, converted from OKLCH to extended sRGB like the Tailwind palette), Tailwind’s radius scale and the embedded fonts. It is the theme of an App whose Theme is nil. Every call returns a new map.
type ThemeValues
Section titled “type ThemeValues”type ThemeValues struct { // contains filtered or unexported fields}ThemeValues are the theme’s values at a component’s position, from UseTheme: the colors resolved for the color scheme there. Use them where classes cannot go: canvases, images tinted in Go, computed styles.
func UseTheme
Section titled “func UseTheme”func UseTheme() ThemeValuesUseTheme returns the theme’s values for the color scheme at the component’s position: the Scheme prop of the nearest element above it that has one (h.Scheme), else the app’s scheme. The component builds again when that scheme or the theme (SetTheme) changes. It is a hook: call it at the top level of a component.
func Spark() tela.Node { th := tela.UseTheme() line := th.Color("chart-1") return Div(Style(tela.Bg(th.Color("muted"))), ...)}func (ThemeValues) Color
Section titled “func (ThemeValues) Color”func (t ThemeValues) Color(name string) ColorColor returns the value of a color token (“primary”) or of a palette color (“red-500”) in the scheme of the values. An unknown name is transparent; in dev mode it panics with the closest token name.
func (ThemeValues) FontMono
Section titled “func (ThemeValues) FontMono”func (t ThemeValues) FontMono() stringFontMono returns the family of font-mono: the theme’s FontMono, or the embedded “JetBrains Mono”.
func (ThemeValues) FontSans
Section titled “func (ThemeValues) FontSans”func (t ThemeValues) FontSans() stringFontSans returns the family of font-sans: the theme’s FontSans, or the embedded “Inter”.
func (ThemeValues) Lookup
Section titled “func (ThemeValues) Lookup”func (t ThemeValues) Lookup(name string) (Color, bool)Lookup returns the value of a color token or palette color, and whether the theme has it.
func (ThemeValues) Radius
Section titled “func (ThemeValues) Radius”func (t ThemeValues) Radius() float32Radius returns the radius of rounded-lg in logical pixels: the theme’s Radius, or Tailwind’s 8 when the theme keeps Tailwind’s scale.
func (ThemeValues) Scheme
Section titled “func (ThemeValues) Scheme”func (t ThemeValues) Scheme() ColorSchemeScheme returns the color scheme of the values, Light or Dark.
func (ThemeValues) Tokens
Section titled “func (ThemeValues) Tokens”func (t ThemeValues) Tokens() []stringTokens returns the names of the theme’s color tokens, sorted.
type TitleBarColors
Section titled “type TitleBarColors”type TitleBarColors = core.TitleBarColorsTitleBarColors are the colors of the title bar and border the OS draws for a window (App.TitleBar, Window.TitleBar). A zero Color, or one with zero alpha, keeps the system’s color; the alpha of any other is ignored (the color is used opaque).
tela.App{ TitleBar: tela.TitleBarColors{ Background: tela.Hex("#1e1b4b"), Text: tela.Hex("#e0e7ff"), }, ...}Windows 11 (build 22000 and later) applies them to the native title bar of a decorated window (Background, Text: the title and the glyphs of the caption buttons) and to its border (Border, also the thin border Windows 11 draws around a Frameless window). Windows 10, Linux (Wayland and X11) and headless ignore them, as does a decorated window on Wayland whose compositor draws no title bar for it. The dark or light title bar already follows the app’s color scheme (App.ColorScheme); these colors are on top of it. Changing the field of an open Window updates the window.
TitleBarColors is an alias of core.TitleBarColors, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type TitleBarColors struct { Background, Text, Border gfx.Color}type Value
Section titled “type Value”type Value[T any] = core.Value[T]Value is an observable value held by one UseValue hook slot: v.Get() reads it, v.Set(x) and v.Update(f) change it. The *Value is the same pointer on every build, so it is comparable and can be passed in props compared by CP or through a context. Set and Update are safe from any goroutine: they queue the change, in order with the state updates, and the UI thread applies it before the next frame. Get is safe from any goroutine too and returns the value the UI thread applied last (a change still in the queue is not visible yet); Latest returns the value as it will be once the queued changes apply, which is what an event handler that has just called Set wants to read. Latest never subscribes anything.
What a change redoes depends on where Get was called; see UseValue. For comparable types, a value == to the current one changes nothing.
Value is an alias of core.Value, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type Value[T any] struct { // contains filtered or unexported fields}func UseBounds
Section titled “func UseBounds”func UseBounds(ref ElementRef) *Value[Rect]UseBounds returns a Value that follows the bounds of the element ref is attached to with h.Ref: its border box in window coordinates, as ElementRef.Bounds returns it (moved by scrolling and transforms, the zero Rect while the element is not mounted or displayed). It is a ResizeObserver that also sees the position: use it to size or place one element after another, or to anchor a floating element.
The Value is updated at the end of every frame, when the bounds changed since the last one, so a component that reads it rebuilds, and a deferred style closure that reads it lays out or repaints, in the frame after the change. Frames where nothing moved cost one comparison and request no further frame. The same Value is returned on every build.
func Meter() tela.Node { track := tela.UseElementRef() b := tela.UseBounds(track) return Div(Ref(track), Class("h-2 rounded bg-slate-200"), Div(Class("h-2 rounded bg-indigo-500"), Style(tela.WidthFn(func() float32 { return b.Get().Width * 0.4 }))))}In an event handler, ElementRef.Bounds gives the same rectangle without a Value: a seek bar turns the pointer’s x into a fraction with e.X-ref.Bounds().X over ref.Bounds().Width.
func UsePresenceTween
Section titled “func UsePresenceTween”func UsePresenceTween(opts ...AnimationOption) *Value[float32]UsePresenceTween is the entrance and the exit of a component inside a child of an h.Presence as one Value: a number that goes from 0 to 1 when the component mounts and from 1 to 0 while its child exits, and that calls UsePresence’s done when the exit arrives, so the child unmounts then. Read it in deferred style closures and the component does not build while it moves.
The options are those of UseTween: Duration (300 ms by default), Ease, and OnDone, which runs after each of the two motions, before done. With spring options (Stiffness, Damping, Bounce, Velocity, Spring) it is a UseSpring instead. The entrance starts from 0, as with Initial; the same *Value is returned on every build.
A toast that slides up and fades in, and out again before it unmounts:
func Toast() tela.Node { return tela.C(toast) }
func toast() tela.Node { shown := tela.UsePresenceTween(tela.Duration(250*time.Millisecond), tela.Ease(tela.EaseOut)) return Div(Class("fixed bottom-8 rounded-xl bg-slate-900 px-5 py-3 text-white"), Style(tela.TranslateFn(func() (float32, float32) { return 0, 24 * (1 - shown.Get()) }), tela.OpacityFn(shown.Get)), Text("Saved"))}
Presence(If(saved, Toast()))Example
t := &exampleT{}defer t.close()toast := func() tela.Node { shown := tela.UsePresenceTween(tela.Duration(200*time.Millisecond), tela.Ease(tela.EaseOut)) return Div(Role("status"), Class("rounded-lg bg-slate-900 px-4 py-2 text-white"), Style(tela.TranslateFn(func() (float32, float32) { return 0, 24 * (1 - shown.Get()) }), tela.OpacityFn(shown.Get)), Text("Saved"))}page := func() tela.Node { saved, setSaved := tela.UseState(true) return Div( Button(OnClick(tela.Toggle(setSaved)), Text("Dismiss")), Presence(If(saved, tela.C(toast))))}app := telatest.Mount(t, tela.C(page))fmt.Println(app.Count(telatest.ByRole("status", "")))start := app.Now()app.Click(telatest.ByRole("button", "Dismiss")) // waits for the exit tweenfmt.Println(app.Count(telatest.ByRole("status", "")), app.Now()-start >= 200*time.Millisecond)// Output:// 1// 0 truefunc UseScroll
Section titled “func UseScroll”func UseScroll(ref ElementRef) (x, y *Value[float32])UseScroll returns two Value objects that follow the scroll offsets of the element ref is attached to (zero while it is not a mounted scrolling element): x is its horizontal offset (scrollLeft) and y its vertical one (scrollTop), in logical pixels. They change on the UI thread as the element scrolls, so a deferred style closure that reads them repaints or lays out only its element, without rebuilding (Motion’s useScroll). The same Values are returned on every build.
func Page() tela.Node { list := tela.UseElementRef() _, y := tela.UseScroll(list) header := Div(Class("h-16 bg-white shadow"), Style(tela.OpacityFn(func() float32 { return 1 - min(y.Get()/200, 1) // fades out over the first 200 px }))) return Div(Class("flex h-screen flex-col"), header, Div(Ref(list), Class("grow overflow-y-auto"), rows()))}Reading y.Get() in the component’s body instead rebuilds the component on every scrolled frame; use h.OnScroll for logic that runs once per frame of scrolling.
func UseSize
Section titled “func UseSize”func UseSize(ref ElementRef) *Value[Size]UseSize returns a Value that follows the size of the element ref is attached to with h.Ref: its border box as laid out, like a ResizeObserver (borderBoxSize). Scrolling and transforms never change it, so it does not move while a list scrolls or a card animates its scale; it is the zero Size while the element is not mounted or not displayed, and for inline elements of a paragraph. Use it to size one element after another, or to make a popover as wide as its trigger.
The Value is updated in every frame that lays out, before painting: a deferred style closure of the paint phase that reads it (TranslateFn, OpacityFn, BgFn) follows in that frame; a component that reads it rebuilds, and a WidthFn or HeightFn lays out, in the next frame. Frames that only scroll or animate transforms do not check it. The same Value is returned on every build.
func Tabs() tela.Node { tab := tela.UseElementRef() size := tela.UseSize(tab) return Div(Class("relative flex"), Button(Ref(tab), Class("px-4 py-2"), Text("Overview")), Div(Class("absolute bottom-0 h-0.5 bg-indigo-500"), Style(tela.WidthFn(func() float32 { return size.Get().Width }))))}Example
t := &exampleT{}defer t.close()var size *tela.Value[tela.Size]feed := func() tela.Node { card := tela.UseElementRef() size = tela.UseSize(card) s := size.Get() // a build reads it: the label follows the next frame return Div(TestID("feed"), Class("h-40 overflow-y-auto"), Div(Ref(card), Class("h-24 w-64 scale-150"), Textf("%.0f x %.0f", s.Width, s.Height)), Div(Class("h-96")), )}app := telatest.Mount(t, tela.C(feed))app.ExpectText("256 x 96") // the layout size: the scale does not countapp.Scroll(telatest.ByTestID("feed"), 0, 80)fmt.Println(size.Get()) // scrolling does not change it either// Output: {256 96}func UseSpring
Section titled “func UseSpring”func UseSpring[T Animatable](target T, opts ...AnimationOption) *Value[T]UseSpring returns a Value that follows target with a spring: on the first build it holds the Initial option’s value (target itself when there is none, so nothing moves) and, if target differs, starts moving to it; whenever a build passes a target that differs from the previous one, the spring retargets from where the value is, keeping its velocity, so an interrupted motion turns smoothly instead of stopping (Compose’s animate*AsState, Motion’s useSpring). T is the type of target, so a float32 target needs a typed value (float32(0), a float32 variable). It is a Value like UseValue’s: read it in a deferred style closure (TranslateFn, OpacityFn, WidthFn…) and the element animates by repainting or laying out only, without rebuilding the component; the same *Value is returned on every build.
The options are [AnimationOption]s: Stiffness and Damping, or Duration and Bounce; without them, Motion’s default spring (stiffness 100, damping 10). The spring ends when it comes to rest (its speed and its distance to the target are below Motion’s thresholds), at exactly the target, and from then on the app requests no frames.
A panel that slides in when open changes, and in from the left when it mounts open:
target := float32(-320)if open { target = 0}x := tela.UseSpring(target, tela.Initial(float32(-320)), tela.Stiffness(300), tela.Damping(30))return Div(Class("fixed inset-y-0 left-0 w-80 bg-white shadow-xl"), Style(tela.TranslateFn(func() (float32, float32) { return x.Get(), 0 })))With reduced motion (App, or the system setting), or in a tree that no frame clock drives (telatest.Render, tela snapshot), the value jumps to each new target. Calling Set on the Value stops the spring; the next target change starts from the value set.
Example
t := &exampleT{}defer t.close()var x *tela.Value[float32]panel := func() tela.Node { open, setOpen := tela.UseState(false) target := float32(-320) if open { target = 0 } x = tela.UseSpring(target, tela.Stiffness(300), tela.Damping(30)) return Div(Class("relative h-full"), Button(OnClick(func(tela.MouseEvent) { setOpen.Set(true) }), Text("Open")), Div(Class("absolute inset-y-0 left-0 w-80 bg-white shadow-xl"), Style(tela.TranslateFn(func() (float32, float32) { return x.Get(), 0 }))))}// NoSettle: the click does not run the spring to its end.app := telatest.Mount(t, tela.C(panel), telatest.NoSettle())app.Click(telatest.ByRole("button", "Open"))for range 3 { app.Advance(100 * time.Millisecond) fmt.Printf("%.1f\n", x.Get())}app.Advance(time.Second) // Advance moves the clock: the spring comes to restfmt.Println(x.Get())// Output:// -140.5// -24.7// -0.1// 0func UseTween
Section titled “func UseTween”func UseTween[T Animatable](target T, opts ...AnimationOption) *Value[T]UseTween is UseSpring with a tween: the value moves to each new target in a fixed Duration along an Ease curve (default 300 ms, CSS’s “ease”), like a CSS transition of the value. A new target starts a new tween from where the value is (tweens have no velocity to keep). Like UseSpring, it starts at the Initial option’s value, or at target.
op := tela.UseTween(target, tela.Duration(200*time.Millisecond), tela.Ease("ease-out"))Div(Class("rounded-lg bg-slate-900 p-3 text-white"), Style(tela.OpacityFn(op.Get)), Text("Saved"))It takes only Duration, Ease, Initial and OnDone; spring options panic in dev mode.
Example
t := &exampleT{}defer t.close()var op *tela.Value[float32]toast := func() tela.Node { shown, setShown := tela.UseState(false) target := float32(0) if shown { target = 1 } op = tela.UseTween(target, tela.Duration(200*time.Millisecond), tela.Ease("linear")) return Div( Button(OnClick(func(tela.MouseEvent) { setShown.Set(true) }), Text("Save")), Div(Class("rounded-lg bg-slate-900 p-3 text-white"), Style(tela.OpacityFn(op.Get)), Text("Saved")))}app := telatest.Mount(t, tela.C(toast), telatest.NoSettle())app.Click(telatest.ByRole("button", "Save"))app.Advance(50 * time.Millisecond)fmt.Printf("%.2f\n", op.Get())app.Advance(150 * time.Millisecond)fmt.Printf("%.2f\n", op.Get())// Output:// 0.25// 1.00func UseValue
Section titled “func UseValue”func UseValue[T any](initial T) *Value[T]UseValue returns the Value of this hook slot: an observable value for something that changes often, such as a drag offset, a scroll position or download progress (ARCHITECTURE section 7, phase-deferred reads, as in Jetpack Compose). The first build stores initial; every build returns the same *Value.
Where v.Get() is called decides what a change redoes:
- in the component’s body while it builds: the component builds again, like with
UseState(also when the components above it skip their build); - inside a layout-phase style closure (
WidthFn,HeightFn): that element is laid out again, with no build and no style computation; - inside a paint-phase style closure (
TranslateFn,OpacityFn,BgFn,TextColorFn): that element is repainted, with no build, style or layout; - anywhere else (event handlers, effects, goroutines): nothing; Get just returns the value.
The reads are taken again on every evaluation, so a closure that stops reading a Value stops being redone by it. A progress bar fed by a goroutine, which lays out the bar again without building Download:
func Download(url string) tela.Node { progress := tela.UseValue(0.0) // from 0 to 1 tela.UseGo(func(ctx context.Context) { fetch(ctx, url, func(done float64) { progress.Set(done) }) // any goroutine }, url) return Div(Class("h-2 w-64 overflow-hidden rounded-full bg-slate-200"), Div(Class("h-full bg-indigo-500"), Style(tela.WidthFn(func() float32 { return float32(256 * progress.Get()) }))))}A dragged card that moves by repainting only (the offset is set from pointer handlers):
type Offset struct{ X, Y float32 }
offset := tela.UseValue(Offset{})card := Div(Class("rounded-xl bg-white p-6 shadow-lg"), Style(tela.TranslateFn(func() (x, y float32) { p := offset.Get() return p.X, p.Y })))Reading the same Value in the body instead (x := offset.Get()) would build the component on every change. Values read by the closures of another window’s tree are not tracked.
Because the *Value is stable and comparable, a struct of Values is a good return value for a custom hook: the caller keeps the struct between builds, passes it in CP props or a context without defeating skipping, and each reader redoes only what it read.
type Drag struct{ X, Y *tela.Value[float32] }
func UseDrag() Drag { return Drag{X: tela.UseValue(float32(0)), Y: tela.UseValue(float32(0))}}In handlers, effects and goroutines, read a Value that may have queued changes with Latest: Get returns the value applied last, and dev mode warns about a Get that misses queued changes.
func (*Value) Get
Section titled “func (*Value) Get”func (v *Value[T]) Get() TGet returns the value. On the UI thread, while a component builds or a deferred style closure is evaluated in layout or paint, the read subscribes what is being evaluated: when the value changes, that component is built again, or that box laid out or repainted, and nothing else. Elsewhere (event handlers, effects) nothing is subscribed.
Get is safe from any goroutine. It returns the value the UI thread applied last: Set and Update calls still waiting in the queue are not visible until the UI thread applies them (on its next wake or frame). In dev mode, a Get outside a build or a deferred closure (a handler, an effect, a goroutine) while changes are queued is reported once per call site, with Latest as the fix (ADR-085).
func (*Value) Latest
Section titled “func (*Value) Latest”func (v *Value[T]) Latest() TLatest returns the value as it will be once the UI thread applies the Set and Update calls queued so far: the applied value (what Get returns) with every pending operation applied to it, in order. Use it in code that reads a Value it just changed, or that another goroutine is changing, before the next frame applies the change:
pos.Set(x)pos.Latest() // x, while pos.Get() is still the old valueAn Update function runs again here, on the calling goroutine, which is why it must be pure (and must not call Latest of its own Value). Latest is safe from any goroutine and never subscribes what is being evaluated, so it does not rebuild or relayout anything when the value changes; reading a Value in a build or in a deferred style closure is what Get is for. A change that has not been queued yet (a Set on another goroutine that has not returned) is not seen; one made through UseScroll or UseBounds is applied by the UI thread directly and is seen by Get as soon as it is made.
func (*Value) Set
Section titled “func (*Value) Set”func (v *Value[T]) Set(x T)Set queues setting the value to x. Safe from any goroutine; the UI thread applies queued updates in order, with the state updates. For comparable types, a value == to the current one when the update applies changes nothing.
func (*Value) Update
Section titled “func (*Value) Update”func (v *Value[T]) Update(f func(T) T)Update queues f, which receives the value as left by the updates queued before it and returns the new one: two queued Update(inc) add 2. f runs on the UI thread when the update applies (and in Latest, on the caller’s goroutine) and must be pure.
type WheelEvent
Section titled “type WheelEvent”type WheelEvent = core.WheelEventWheelEvent is passed to h.OnWheel: a mouse wheel notch or a touchpad scroll over the element (the DOM’s wheel event). DeltaX and DeltaY are the distance in logical pixels with the DOM’s signs (positive DeltaY scrolls down; a notch is 53 pixels, and Shift turns a vertical notch horizontal); X, Y, LocalX and LocalY and the modifiers are as in MouseEvent. It bubbles, and its default action scrolls the nearest scrolling element that can move that way: PreventDefault cancels it.
// Ctrl+wheel zooms a canvas instead of scrolling the page.Div(OnWheel(func(e tela.WheelEvent) { if e.Ctrl { e.PreventDefault() zoom.Update(func(z float32) float32 { return z * (1 - e.DeltaY/500) }) }}))WheelEvent is an alias of core.WheelEvent, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type WheelEvent struct { // X and Y are the pointer position in the window, LocalX and LocalY // relative to the border box of the element whose handler runs (see // MouseEvent). X, Y, LocalX, LocalY float32 // DeltaX and DeltaY are the scroll distance in logical pixels, with // the DOM's signs: positive DeltaY scrolls down (toward the end of the // content), positive DeltaX to the right. A wheel notch is 53 pixels; // Shift turns a notch of a vertical wheel into a horizontal one. DeltaX, DeltaY float32 // Modifier keys held during the event. Shift, Ctrl, Alt, Meta bool // contains filtered or unexported fields}func (WheelEvent) DefaultPrevented
Section titled “func (WheelEvent) DefaultPrevented”func (e WheelEvent) DefaultPrevented() boolDefaultPrevented reports whether a handler called PreventDefault.
func (WheelEvent) PreventDefault
Section titled “func (WheelEvent) PreventDefault”func (e WheelEvent) PreventDefault()PreventDefault cancels the scroll the event would cause.
func (WheelEvent) StopPropagation
Section titled “func (WheelEvent) StopPropagation”func (e WheelEvent) StopPropagation()StopPropagation stops the event from bubbling (see MouseEvent).
type Window
Section titled “type Window”type Window struct { // Title is the window title. Title string // Width and Height are the size of the content area in logical // pixels. Zero means the platform's default size (800×600); set both // or neither. Width, Height float32 // MinWidth, MinHeight, MaxWidth and MaxHeight limit the size the // user can give the window; zero is no limit on that side. MinWidth, MinHeight, MaxWidth, MaxHeight float32 // FixedSize keeps the user from resizing the window. FixedSize bool // Frameless removes the OS title bar and borders: the content draws // its own title bar, marked with h.WindowDrag and h.WindowControl. // The window stays resizable at its edges (unless FixedSize). Frameless bool // AlwaysOnTop keeps the window above other windows (not on Wayland, // which has no way to ask for it). AlwaysOnTop bool // Modal makes the window modal to the window it is declared in: that // window takes no input while this one is visible (a press there // brings this one forward). Modal bool // Hidden hides the window: it stays open, with its state, until // Hidden is false again. A hidden window draws nothing, but its // components build and its effects run as in a shown one. Hidden bool // Icon is the window's icon (title bar, task bar, alt-tab), the same // picture at several sizes (16 to 256 pixels; the OS picks). Empty is // the app's default icon. Icon []image.Image // TitleBar sets the colors of the native title bar and border on // Windows 11; see [TitleBarColors]. The zero value keeps the // system's. Other platforms ignore it. TitleBar TitleBarColors // Backdrop is the system material behind the window (Mica, Mica Alt, // Acrylic) on Windows 11 22H2; see [Backdrop]. The zero value is the // system's choice. Other platforms ignore it. Backdrop Backdrop // RootClass are Tailwind classes for the window's root, which fills // the window, as App.RootClass for the main window ("bg-background"). RootClass string // Placement is where the window opens: a WindowPlacement saved from // [WindowHandle].Placement, so the window comes back where the user // left it. Its size, when set, wins over Width and Height. The zero // value lets the OS place the window. Placement WindowPlacement // OnClose runs when the user asks to close the window. Update the // state that renders this Window there. OnClose func() // Root is the content of the window: a struct component value // (Root: Settings{}) or a function component made with C. Root Component}Window is a component that opens a window while it is mounted and closes it when it unmounts: whether a window is open is state, like whether a dialog is shown. It renders nothing where it is declared; its Root is the content of the new window.
func Notes() tela.Node { settingsOpen, setSettingsOpen := tela.UseState(false) return Div( Button(OnClick(func() { setSettingsOpen.Set(true) }), Text("Settings")), If(settingsOpen, tela.Component(tela.Window{ Title: "Settings", Width: 480, Height: 360, Modal: true, OnClose: func() { setSettingsOpen.Set(false) }, Root: SettingsPanel{}, })), )}The window belongs to the window it is declared in: it stays above it, and with Modal that window takes no input while this one is visible. The app has one tree of components across its windows: Root is built by the component that declares the Window, so it sees that component’s state and props, and the contexts above it reach the new window (UseContext); a Value read in the new window rebuilds it when it changes. Each window has its own layout, focus, hover, overlays (h.Portal), cursor and scale; the theme, the class aliases and the color scheme are the app’s.
When the user asks to close the window (its close button, Alt+F4, a WindowClose control, WindowHandle.Close), OnClose runs: it should update the state that renders the Window, which unmounts it and closes the window. Without OnClose the request does nothing and the window stays open (dev mode warns once). To keep the window and its state while it is out of sight, set Hidden instead of unmounting it.
The fields are applied when they change: a new Title, Width and Height, size limits, AlwaysOnTop, Hidden, Icon, TitleBar, Backdrop or RootClass update the open window. FixedSize, Frameless, Modal and Placement are read when it opens (give the Window a new key to open it again with others).
tela snapshot, tela inspect and tela mcp show the main window only; in tests, telatest’s App.Windows and App.Window reach the others. Under tela dev the other windows keep their parent, modality and window control, and an open window survives a reload (it is keyed by its place in the tree).
func (Window) Build
Section titled “func (Window) Build”func (w Window) Build() NodeBuild opens the window while the component is mounted (see Window).
type WindowControl
Section titled “type WindowControl”type WindowControl = core.WindowControlWindowControl is what a window-control button of a custom title bar does, given to h.WindowControl.
WindowControl is an alias of core.WindowControl, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type WindowControl uint8const ( // WindowMinimize minimizes the window. WindowMinimize WindowControl = iota + 1 // WindowMaximize maximizes the window, or restores a maximized one. WindowMaximize // WindowClose asks to close the window, as the OS's close button // does: the window's OnClose runs (for the main window, App.OnClose, // or the app quits). WindowClose)func (WindowControl) String
Section titled “func (WindowControl) String”func (c WindowControl) String() stringtype WindowHandle
Section titled “type WindowHandle”type WindowHandle = core.WindowHandleWindowHandle is a window of the app: the one a component renders in (UseWindow), or the main window given to App.OnClose. It is a small comparable value, the same for the window’s whole life, with these methods:
- Minimize, Maximize, Unmaximize, ToggleMaximize, SetFullscreen(bool): ask the OS to change the window’s state.
- Hide and Show: hide the window (it stays open, with its state) and show it again (activated). The app keeps running while its windows are hidden: App.OnClose can hide the main window to keep the app in the tray. A hidden or minimized window draws nothing, but its components build, its effects run and its Windows open as usual (a tray menu declared in it follows its state); it draws the current state when it shows.
- Focus: raise the window and give it the keyboard focus, bringing it back from minimized.
- Close: ask to close the window as its close button does (its OnClose runs; for the main window App.OnClose, or the app quits).
- State() WindowState: maximized, fullscreen, minimized, focused, hidden and whether the app draws the title bar (ClientSideDecorations). Read in a component’s body, it rebuilds the component when the state changes.
- Placement() WindowPlacement: where the window is, to save and give back as App.Placement or Window.Placement next time.
- IsZero() bool: the zero handle (no window).
The requests are safe from any goroutine: they are made on the UI thread, in order with the state updates. The OS may refuse one (a tiling window manager does not maximize); State says what happened. The handle of a closed window, or one in tela snapshot (no window), does nothing.
WindowHandle is an alias of core.WindowHandle, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type WindowHandle struct { // contains filtered or unexported fields}func UseWindow
Section titled “func UseWindow”func UseWindow() WindowHandleUseWindow returns the handle of the window the component renders in: the main window, or the Window it is inside of.
func titleBar() tela.Node { win := tela.UseWindow() maximize := "Maximize" if win.State().Maximized { // the component rebuilds when it changes maximize = "Restore" } return Div(Class("flex h-9 items-center"), WindowDrag(), Span(Class("grow px-3 text-sm"), Text("Notes")), Button(WindowControl(tela.WindowMinimize), AriaLabel("Minimize"), Text("–")), Button(WindowControl(tela.WindowMaximize), AriaLabel(maximize), Text("□")), Button(WindowControl(tela.WindowClose), AriaLabel("Close"), Text("×")), )}func (WindowHandle) Close
Section titled “func (WindowHandle) Close”func (w WindowHandle) Close()Close asks to close the window, as the user does with the title bar’s close button: the window’s OnClose runs (it removes the Window from the state that renders it); for the main window App.OnClose runs, or the app quits.
func (WindowHandle) Focus
Section titled “func (WindowHandle) Focus”func (w WindowHandle) Focus()Focus asks the OS to raise the window and give it the keyboard focus, restoring it if it is minimized. The OS may refuse (focus stealing prevention) and flash the window instead.
func (WindowHandle) Hide
Section titled “func (WindowHandle) Hide”func (w WindowHandle) Hide()Hide hides the window. It stays open (mounted, with its state and effects) until it is shown again or closed; the app keeps running while its windows are hidden (“close to tray”). A hidden window draws nothing, but its components still build and its effects run; it draws the current state when it is shown.
func (WindowHandle) IsZero
Section titled “func (WindowHandle) IsZero”func (w WindowHandle) IsZero() boolIsZero reports whether w is the zero WindowHandle (no window).
func (WindowHandle) Maximize
Section titled “func (WindowHandle) Maximize”func (w WindowHandle) Maximize()Maximize asks the OS to maximize the window.
func (WindowHandle) Minimize
Section titled “func (WindowHandle) Minimize”func (w WindowHandle) Minimize()Minimize asks the OS to minimize the window; Focus brings it back.
func (WindowHandle) Placement
Section titled “func (WindowHandle) Placement”func (w WindowHandle) Placement() WindowPlacementPlacement returns where the window is (WindowPlacement): what an app saves to open the window there next time. It is kept after the window closes. Safe from any goroutine.
func (WindowHandle) SetFullscreen
Section titled “func (WindowHandle) SetFullscreen”func (w WindowHandle) SetFullscreen(fullscreen bool)SetFullscreen asks the OS to make the window fullscreen or to leave fullscreen.
func (WindowHandle) Show
Section titled “func (WindowHandle) Show”func (w WindowHandle) Show()Show shows a hidden window and activates it.
func (WindowHandle) State
Section titled “func (WindowHandle) State”func (w WindowHandle) State() WindowStateState returns the window’s state. Read in a component’s build, it subscribes the component: it builds again when the state changes. Elsewhere (handlers, effects, goroutines) it only reads it.
func (WindowHandle) ToggleMaximize
Section titled “func (WindowHandle) ToggleMaximize”func (w WindowHandle) ToggleMaximize()ToggleMaximize maximizes the window, or restores it when it is maximized (what a title bar’s maximize button does).
func (WindowHandle) Unmaximize
Section titled “func (WindowHandle) Unmaximize”func (w WindowHandle) Unmaximize()Unmaximize asks the OS to restore a maximized window to its size.
type WindowPlacement
Section titled “type WindowPlacement”type WindowPlacement = core.WindowPlacementWindowPlacement is where a window is: Width and Height (its logical size outside maximized and fullscreen), X and Y (the position in physical pixels of the desktop, when HasPosition: never on Wayland), Maximized, Fullscreen and RestoreToken (the OS’s session restore token; on Wayland it lets the compositor put the window back where supported). Save it (WindowHandle.Placement) and give it back as App.Placement or Window.Placement: the window opens where the user left it. The zero value means nothing is known.
WindowPlacement is an alias of core.WindowPlacement, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type WindowPlacement struct { // Width and Height are the logical size of the content area outside // maximized and fullscreen (the size it returns to); zero is // unknown. Width, Height float32 // X and Y are the top-left of the content area in physical pixels of // the OS's desktop, when HasPosition is set (never on Wayland, which // does not let apps place windows; RestoreToken does it there where // the compositor supports it). X, Y int HasPosition bool // Maximized and Fullscreen are the state to open in. Maximized, Fullscreen bool // RestoreToken is an opaque token the OS uses to put the window back // ("" where none is needed). RestoreToken string}type WindowState
Section titled “type WindowState”type WindowState = core.WindowStateWindowState is the state of a window (WindowHandle.State): Maximized, Fullscreen and Minimized as the OS reports them (Wayland cannot report minimized windows), Focused (the active window), Hidden (the app hid it) and ClientSideDecorations (the OS draws no title bar: the app draws one, as a frameless window does, and so on a Wayland desktop without server-side decorations).
WindowState is an alias of core.WindowState, declared in an internal package of the module. pkg.go.dev shows only the alias; the exported fields and methods of the aliased type, listed here, are part of the API:
type WindowState struct { // Maximized, Fullscreen and Minimized are the window's OS state as // the OS reported it (Wayland cannot report minimized windows). Maximized, Fullscreen, Minimized bool // Focused: the window has the keyboard focus (it is the active // window). Focused bool // Hidden: the app hid the window (Hide, or Hidden). Hidden bool // ClientSideDecorations: the OS draws no title bar or borders for the // window (a Frameless window, or a Wayland compositor without // server-side decorations), so the app draws its own title bar. ClientSideDecorations bool}