st

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Aug 11, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Overview

Package st is a from-scratch, standard-library-only Go port of Python's Streamlit: a framework for building interactive web and data apps by writing a plain script.

The model

You write an app function with the signature func(s *st.Session). Inside it you call methods on the session to build the page: s.Title, s.Write, s.Slider, s.Button and so on. Each call appends one element to the page's element tree, and each widget call returns the widget's current value. The framework runs your app function top to bottom to produce the page.

The defining behaviour of Streamlit, reproduced faithfully here, is rerun-on-interaction. When the user interacts with any widget, the entire app function runs again from the top. Widget values are restored from per-session state, so a slider you dragged reads its new position on the next run, and any State you stored persists too. The freshly built element tree is diffed against the page and the browser updates. This means app code can be written as a simple straight-line script: there are no callbacks, event handlers, or manual DOM updates.

Two rules follow from that model and are worth internalising early. Session.Stop halts a run and Session.Rerun abandons one and starts it again from the top. And widget state lives exactly as long as the app keeps rendering the widget: state for a widget a run did not draw is discarded at the end of that run, so hiding and revealing a widget starts it from its default — the same behaviour as Streamlit. Give any widget that is not unconditionally rendered an explicit key.

Sessions and containers

A Session represents one browser connection. It embeds the root Container, so all display and widget methods are available directly on the session. Layout helpers such as Container.Columns and Container.Expander return further containers that render nested regions; Session.Sidebar returns the sidebar container. Because every method lives on *Container, the same API works uniformly for the main body, the sidebar and each column.

Transport and frontend

Run starts an HTTP server. It serves a small, dependency-free single-page frontend (embedded via go:embed) that renders the JSON element tree and posts widget-change events back to POST /api/run. The server applies the event, reruns the app function for that session, and returns the new tree. The whole protocol is plain JSON request/response — no third-party modules, no JavaScript frameworks, no external charting library (charts are rendered to inline SVG on the server).

Example

package main

import "github.com/malcolmston/streamlit/st"

func main() {
	st.Run(app, ":8501")
}

func app(s *st.Session) {
	s.Title("Hello, Streamlit-Go")
	n := s.Slider("Points", 0, 100, 50, 1)
	s.LineChart(series(int(n)))
	if s.Button("Celebrate") {
		s.Success("🎉")
	}
}

Widgets, layout, media and charts

Beyond the basics the package offers a broad surface, each piece backed by per-session state and rendered by the embedded frontend:

Safety

Text rendered as Markdown is escaped before any formatting is applied, and a link or media URL is emitted only if its scheme is on an allowlist, so a javascript: target cannot reach an href. Raw HTML is opt-in through Container.Html and Container.MarkdownUnsafe. Both POST endpoints reject a request whose Origin header names another site, and every allocation a remote caller can grow — sessions, uploaded bytes, request bodies, cache entries, widget keys — is bounded; see Options.

Deferred features

This is a compact reimplementation of a large framework. Deliberately deferred: custom components, multipage apps, fragments, real-time streaming/async widgets, in-place dataframe editing, query parameters and theming APIs. The synchronous long-poll-free transport also means Container.Spinner and Container.Progress are snapshots of the completed run rather than live-updating during work. The full list, and every place this port's semantics differ from upstream on purpose, is in API-DEVIATIONS.md.

Index

Examples

Constants

View Source
const (
	// DefaultMaxSessions is the largest number of concurrent sessions kept in
	// memory. When the limit is reached the least recently used session is
	// evicted.
	DefaultMaxSessions = 1000
	// DefaultSessionIdleTimeout is how long a session survives without a
	// request before it is dropped.
	DefaultSessionIdleTimeout = 30 * time.Minute
	// DefaultMaxUploadBytes is the largest accepted body for a single
	// multipart upload request, across all of its file parts.
	DefaultMaxUploadBytes int64 = 32 << 20 // 32 MiB
	// DefaultMaxRequestBytes is the largest accepted body for POST /api/run.
	DefaultMaxRequestBytes int64 = 1 << 20 // 1 MiB
	// DefaultMaxWidgetEntries is the largest number of widget-state entries a
	// single session may retain.
	DefaultMaxWidgetEntries = 1024
	// DefaultMaxWidgetStateBytes is the largest total size of the values held
	// in one session's widget state.
	DefaultMaxWidgetStateBytes int64 = 1 << 20 // 1 MiB
)

Defaults applied by Handler and Run. Every one of them exists because the value it bounds is ultimately chosen by a remote client: without a ceiling a single caller could pin unbounded memory (sessions, uploaded bytes) on the server. Use Options with HandlerWithOptions to tune them.

View Source
const DefaultMaxCacheEntries = 1024

DefaultMaxCacheEntries bounds the process-wide table used by Session.Cache. Streamlit's @st.cache_data defaults to max_entries=None (unbounded); this port bounds it because a cache whose keys are derived from user input otherwise grows until the process dies. Change it with CacheSetMaxEntries.

Variables

This section is empty.

Functions

func CacheClear added in v0.2.0

func CacheClear()

CacheClear removes all entries from the process-wide cache used by Session.Cache. It is primarily useful in tests and for manual invalidation. Resources registered with Session.CacheResource survive; clear those with CacheResourceClear.

func CacheDelete added in v0.4.0

func CacheDelete(key string) bool

CacheDelete removes a single entry from the data cache used by Session.Cache, forcing the next call for that key to recompute. It reports whether an entry was present. It is the targeted counterpart to CacheClear, matching the per-function .clear() Streamlit exposes on a cached function.

func CacheLen added in v0.4.0

func CacheLen() int

CacheLen reports how many entries the data cache currently holds. Resources registered with Session.CacheResource are not counted.

func CacheResourceClear added in v0.4.0

func CacheResourceClear()

CacheResourceClear discards every singleton registered with Session.CacheResource, so the next call for each key builds a fresh one. It mirrors st.cache_resource.clear() and is chiefly useful in tests.

func CacheSetMaxEntries added in v0.4.0

func CacheSetMaxEntries(n int)

CacheSetMaxEntries sets how many entries Session.Cache retains. When the table is full the entry inserted longest ago is evicted. A value of zero or less restores DefaultMaxCacheEntries. It affects Session.Cache only; Session.CacheResource entries are never evicted.

func Handler

func Handler(app func(*Session)) http.Handler

Handler returns the http.Handler that serves the app with the default Options. It is exposed so the app can be mounted inside a larger server or driven in tests; most callers should use Run instead.

func HandlerWithOptions added in v0.4.0

func HandlerWithOptions(app func(*Session), opts Options) http.Handler

HandlerWithOptions is Handler with explicit resource limits and origin policy. See Options.

func Run

func Run(app func(*Session), addr string) error

Run starts an HTTP server that serves the app on addr (for example ":8501"). Each browser connection is assigned its own Session; widget interactions rerun the app function and push the updated element tree back. Run blocks until the server exits.

func RunWithOptions added in v0.4.0

func RunWithOptions(app func(*Session), addr string, opts Options) error

RunWithOptions is Run with explicit resource limits and origin policy.

Types

type Container

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

Container is a region of the page into which elements are appended. The root container is embedded in Session so its methods are reachable directly on the session; layout helpers such as Container.Columns and Container.Expander return additional containers that render nested regions.

Every display and widget method lives on *Container, which is what lets the same API be used for the main body, the sidebar, and individual columns.

Example (ColumnsWeighted)

ExampleContainer_columnsWeighted lays out a wide chart beside a narrow summary, mirroring st.columns([3, 1]).

app := func(s *Session) {
	cols := s.ColumnsWeighted([]float64{3, 1})
	cols[0].LineChart([]float64{1, 4, 9})
	cols[1].Metric("Peak", "9", "+5")
}

s := newSession()
row := s.run(app).Children[1].Children[0]
for _, col := range row.Children {
	fmt.Printf("%v -> %s\n", col.Props["weight"], col.Children[0].Type)
}
Output:
3 -> chart
1 -> metric
Example (MarkdownUnsafe)

ExampleContainer_markdownUnsafe contrasts the safe default with the opt-in. Markdown ships the text for escaping in the browser; MarkdownUnsafe flags it to be passed through as HTML, which is why it must never carry untrusted input.

app := func(s *Session) {
	s.Markdown(`<b>from a user</b>`)
	s.MarkdownUnsafe(`<b>from me</b>`)
}

s := newSession()
for _, el := range s.run(app).Children[1].Children {
	fmt.Println(el.Props["text"], "unsafe:", el.Props["unsafeAllowHTML"])
}
Output:
<b>from a user</b> unsafe: <nil>
<b>from me</b> unsafe: true

func (*Container) AreaChart

func (c *Container) AreaChart(series ...[]float64)

AreaChart adds a filled area chart. See Container.LineChart for the series convention.

func (*Container) Audio added in v0.2.0

func (c *Container) Audio(src any)

Audio adds an audio player. src may be a URL string or raw audio bytes (for example WAV or MP3), which are embedded as a data URI.

func (*Container) AudioInput added in v0.3.0

func (c *Container) AudioInput(label string, key ...string) []UploadedFile

AudioInput adds a control that records audio from the user's microphone and returns the recorded files for the current session, mirroring Streamlit's st.audio_input. It works like Container.CameraInput, receiving bytes over the multipart /api/upload endpoint keyed by the widget key.

func (*Container) Badge added in v0.3.0

func (c *Container) Badge(label string, color ...string)

Badge adds a small coloured pill label, mirroring Streamlit's st.badge. color is an optional colour name (for example "blue", "green", "red", "orange", "violet" or "grey"); an empty or unrecognised colour defaults to "blue".

func (*Container) Balloons added in v0.3.0

func (c *Container) Balloons()

Balloons triggers the celebratory balloons animation, mirroring Streamlit's st.balloons. It adds a one-shot effect element to the page.

func (*Container) BarChart

func (c *Container) BarChart(series ...[]float64)

BarChart adds a bar chart. See Container.LineChart for the series convention. Multiple series are drawn as grouped bars.

func (*Container) BorderedContainer added in v0.3.0

func (c *Container) BorderedContainer() *Container

BorderedContainer adds a nested grouping region drawn with a visible border and returns a container for it, mirroring Streamlit's st.container(border= True). It behaves like Container.Container but is visually delimited, which is useful for grouping related output into a card.

func (*Container) Button

func (c *Container) Button(label string, key ...string) bool

Button adds a clickable button and returns true on the single run triggered by a click. An optional stable key may be supplied as the final argument.

func (*Container) CameraInput added in v0.3.0

func (c *Container) CameraInput(label string, key ...string) []UploadedFile

CameraInput adds a control that captures a photo from the user's webcam and returns the captured image files for the current session, mirroring Streamlit's st.camera_input. Like Container.FileUploader the bytes arrive over the multipart /api/upload endpoint keyed by the widget key and are held in session state; the returned slice is empty until a photo is taken.

func (*Container) Caption

func (c *Container) Caption(text string)

Caption adds small, muted caption text (rendered as markdown).

func (*Container) ChatInput added in v0.2.0

func (c *Container) ChatInput(placeholder string, key ...string) string

ChatInput adds a chat entry box pinned to the bottom of its region and returns the message the user last submitted, or the empty string before any submission. Submitting a message (pressing Enter) reruns the app with the new value available. An optional stable key may be supplied.

if msg := s.ChatInput("Ask me anything"); msg != "" {
	s.ChatMessage("user").Text(msg)
}

func (*Container) ChatMessage added in v0.2.0

func (c *Container) ChatMessage(role string) *Container

ChatMessage adds a chat message bubble attributed to role (commonly "user" or "assistant") and returns a container for the message body. Any elements may be placed inside it, so a message can contain markdown, tables, charts, and so on.

m := s.ChatMessage("assistant")
m.Markdown("Here is your **answer**.")

func (*Container) Checkbox

func (c *Container) Checkbox(label string, def bool, key ...string) bool

Checkbox adds a checkbox initialised to def and returns its current state.

func (*Container) Code

func (c *Container) Code(code, lang string)

Code adds a syntax-highlight-styled code block. lang is an advisory language label (for example "go" or "python") and may be empty.

func (*Container) ColorPicker added in v0.2.0

func (c *Container) ColorPicker(label, def string, key ...string) string

ColorPicker adds a colour selector and returns the chosen colour as a "#rrggbb" hex string. def is the initial value; an empty def defaults to black ("#000000").

func (*Container) Columns

func (c *Container) Columns(n int) []*Container

Columns splits the current region into n side-by-side columns and returns a container for each. Elements added to a returned container render within that column. If n is less than one it is treated as one.

c1, c2 := s.Columns(2)[0], s.Columns(2)[1] // (illustrative)
cols := s.Columns(2)
cols[0].Metric("Left", "1", "")
cols[1].Metric("Right", "2", "")

func (*Container) ColumnsWeighted added in v0.4.0

func (c *Container) ColumnsWeighted(weights []float64) []*Container

ColumnsWeighted splits the current region into columns whose widths are proportional to weights, mirroring Streamlit's st.columns([2, 1]) — which takes a list of relative widths rather than a count.

Non-positive and non-finite weights are treated as 1 so a stray zero cannot collapse a column to nothing. An empty weights slice yields a single full-width column.

cols := s.ColumnsWeighted([]float64{3, 1})
cols[0].LineChart(series) // three quarters of the width
cols[1].Metric("Peak", "42", "")

func (*Container) Container

func (c *Container) Container() *Container

Container adds a nested, undecorated grouping region and returns a container for it. It is useful for grouping elements or for building output out of order.

func (*Container) DataFrame

func (c *Container) DataFrame(data any, caption ...string)

DataFrame renders tabular data like Container.Table but adds a client-side sorting hint, so column headers can be clicked to sort the rows in the browser. It mirrors Streamlit's st.dataframe entry point and accepts an optional caption.

func (*Container) DateInput added in v0.2.0

func (c *Container) DateInput(label, def string, key ...string) string

DateInput adds a calendar date field and returns the selected date as an ISO-8601 string ("2006-01-02"). def is the initial value and may be empty.

func (*Container) DateRangeInput added in v0.3.0

func (c *Container) DateRangeInput(label, defStart, defEnd string, key ...string) (string, string)

DateRangeInput adds a calendar control that selects a start and end date and returns them as ISO-8601 strings ("2006-01-02"), mirroring Streamlit's st.date_input used with a tuple default. defStart and defEnd are the initial values and may be empty. The earlier date is always returned first.

func (*Container) Divider

func (c *Container) Divider()

Divider adds a horizontal rule.

func (*Container) DownloadButton added in v0.2.0

func (c *Container) DownloadButton(label, filename string, data []byte, key ...string) bool

DownloadButton adds a button that downloads data as a file named filename when clicked, and returns true on the single run triggered by the click. The bytes are embedded in the page as a base64 data URI, so this is best suited to modestly sized payloads. The content type is detected from the data.

func (*Container) Echo added in v0.3.0

func (c *Container) Echo(code string)

Echo adds a read-only display of Go source code, mirroring Streamlit's st.echo (which shows the code inside its block). The code is rendered as a syntax-styled block tagged as Go.

func (*Container) Empty added in v0.2.0

func (c *Container) Empty() *Container

Empty adds a single placeholder region and returns a container for it. Because the element tree is rebuilt on every run, an Empty is most useful as a stable slot whose contents are decided later in the same run.

func (*Container) Error

func (c *Container) Error(text string)

Error adds a red error message box.

func (*Container) Exception added in v0.3.0

func (c *Container) Exception(err error)

Exception adds a formatted error box for err, mirroring Streamlit's st.exception. The error's message and its Go type name are shown. A nil error renders an empty exception box.

func (*Container) Expander

func (c *Container) Expander(label string, expanded bool) *Container

Expander adds a collapsible section with the given label and returns a container for its body. When expanded is true the section starts open.

func (*Container) Feedback added in v0.2.0

func (c *Container) Feedback(kind string, key ...string) int

Feedback adds a rating control and returns the selected score, or -1 when nothing has been chosen yet. kind selects the style: "stars" yields a 0–4 five-star rating and "thumbs" yields a 0 (down) / 1 (up) control. Any other value is treated as "stars".

func (*Container) FileUploader added in v0.2.0

func (c *Container) FileUploader(label string, key ...string) []UploadedFile

FileUploader adds a file selection control and returns the files uploaded for it in the current session. Bytes are received over a multipart POST to /api/upload and held in session state (they are not part of the JSON element tree); only filenames are echoed to the browser. The returned slice is empty until the user uploads at least one file.

func (*Container) Form added in v0.2.0

func (c *Container) Form(key string) *Container

Form adds a form region identified by key and returns a container for its body. Widgets appended to the returned container defer their state updates: interacting with them does not rerun the app. Instead the browser stages their values locally and commits them all at once when a Container.FormSubmitButton inside the form is clicked, at which point the app reruns with every staged value applied together.

This batching is the point of a form: several inputs can be changed and then submitted as a unit, avoiding a rerun per keystroke.

f := s.Form("signup")
name := f.TextInput("Name", "")
age := f.NumberInput("Age", 18)
if f.FormSubmitButton("Register") {
	s.Success("Welcome, " + name)
	_ = age
}

func (*Container) FormSubmitButton added in v0.2.0

func (c *Container) FormSubmitButton(label string) bool

FormSubmitButton adds the submit button for the enclosing form and returns true on the single run triggered by its click. It must be called on a container returned by Container.Form; used elsewhere it behaves like a disconnected button that never batches values.

func (*Container) Header

func (c *Container) Header(text string)

Header adds a section header.

func (*Container) Help added in v0.3.0

func (c *Container) Help(value any)

Help adds an introspective description of value, mirroring Streamlit's st.help. The value's Go type and its formatted representation are shown, which is handy for quickly inspecting a variable while building an app.

func (*Container) Histogram added in v0.2.0

func (c *Container) Histogram(data []float64, bins int)

Histogram adds a histogram of data grouped into the given number of bins (clamped to at least one), rendered as a bar chart. It is a convenience over bucketing the data yourself and calling Container.BarChart.

func (*Container) Html added in v0.3.0

func (c *Container) Html(html string)

Html adds a block of raw, unescaped HTML, mirroring Streamlit's st.html. The markup is inserted verbatim, so only pass HTML you trust — untrusted input can inject script into the page.

func (*Container) Image added in v0.2.0

func (c *Container) Image(src any, caption ...string)

Image adds an image. src may be a URL string, PNG/JPEG (or other) bytes, or an image.Image value, which is encoded to PNG. An optional caption is shown beneath the image.

func (*Container) Info

func (c *Container) Info(text string)

Info adds a blue informational message box.

func (*Container) JSON

func (c *Container) JSON(value any, collapsed ...bool)

JSON adds a pretty-printed JSON view of value. Values that cannot be marshalled are rendered using their Go default formatting instead. When the optional collapsed argument is true the view starts collapsed behind a disclosure toggle in the browser.

func (*Container) Latex added in v0.3.0

func (c *Container) Latex(expr string)

Latex adds a block of mathematics written in LaTeX. expr is the raw LaTeX source without surrounding delimiters, for example `\int_a^b f(x)\,dx`. It mirrors Streamlit's st.latex; the embedded frontend renders the expression in a dedicated math block.

func (*Container) LineChart

func (c *Container) LineChart(series ...[]float64)

LineChart adds a line chart. Each argument is one numeric series; series are plotted against a shared 0..N-1 x-axis and rendered to inline SVG on the server using only the standard library.

func (*Container) LinkButton added in v0.3.0

func (c *Container) LinkButton(label, url string)

LinkButton adds a button that navigates to url when clicked, mirroring Streamlit's st.link_button. Unlike Container.Button it does not rerun the app; it is a styled hyperlink.

func (c *Container) Logo(src any)

Logo adds a small brand image, typically shown at the top of the app or sidebar. src accepts the same values as Container.Image.

func (*Container) Map added in v0.2.0

func (c *Container) Map(points []MapPoint)

Map adds a simple point map. Each point is projected with an equirectangular projection and drawn as a dot over a framed world extent, rendered to inline SVG on the server using only the standard library.

func (*Container) Markdown

func (c *Container) Markdown(text string)

Markdown adds text rendered with a small, safe subset of Markdown (ATX headings, bold, italics, inline code, links and unordered lists) by the frontend.

The text is treated as untrusted: every character is HTML-escaped before any formatting is applied, and a link target is emitted only when its scheme is one of http, https, mailto, tel, ftp, ftps or sms — a `javascript:` URL is replaced with "#". This mirrors Streamlit, where st.markdown escapes HTML unless unsafe_allow_html is set; see Container.MarkdownUnsafe for the opt-in.

func (*Container) MarkdownUnsafe added in v0.4.0

func (c *Container) MarkdownUnsafe(text string)

MarkdownUnsafe is Container.Markdown with HTML passed through instead of escaped, mirroring st.markdown(body, unsafe_allow_html=True).

The name is a warning, not decoration: anything in text that looks like a tag becomes a tag, so a string containing untrusted input can inject script into every viewer's page. Use Container.Markdown unless the whole string is under your control. Markdown link targets are still restricted to safe schemes, but raw <a href="javascript:…"> in the HTML is not — that is the point of the opt-in.

func (*Container) Metric

func (c *Container) Metric(label, value, delta string)

Metric adds a big-number metric with an optional delta indicator. A delta beginning with '-' renders as a negative (downward) change; the coloring can be flipped or disabled with Container.MetricColored.

Alongside the raw delta text, the resolved arrow direction ("up", "down" or "none") and delta colour ("green", "red" or "grey") are attached to the element, matching how Streamlit's st.metric derives them; see Container.MetricColored for the exact rules.

func (*Container) MetricColored added in v0.2.0

func (c *Container) MetricColored(label, value, delta, deltaColor string)

MetricColored is like Container.Metric but controls how the delta is coloured. deltaColor is one of "normal" (positive green, negative red), "inverse" (the reverse, useful when lower is better), or "off" (grey).

The element records the resolved "color" ("green", "red" or "grey") and "direction" ("up", "down" or "none") in addition to the raw delta text and deltaColor mode, mirroring Streamlit's st.metric. See [metricDeltaSignal] for how the sign of the delta text is interpreted.

func (*Container) MultiSelect

func (c *Container) MultiSelect(label string, options []string, key ...string) []string

MultiSelect adds a multiple-selection control and returns the currently selected options. Selections not present in options are dropped.

func (*Container) NumberInput

func (c *Container) NumberInput(label string, def float64, key ...string) float64

NumberInput adds a numeric entry field initialised to def and returns its current value.

func (*Container) NumberInputRange added in v0.3.0

func (c *Container) NumberInputRange(label string, min, max, def float64, key ...string) float64

NumberInputRange adds a numeric entry field bounded to the inclusive range [min, max] and returns its current value clamped to that range, mirroring Streamlit's st.number_input(min_value=…, max_value=…). def is the initial value and is itself clamped.

func (c *Container) PageLink(url, label string)

PageLink adds a navigational link to url shown with the given label, mirroring Streamlit's st.page_link. It is rendered as a prominent link rather than a button.

func (*Container) PasswordInput added in v0.3.0

func (c *Container) PasswordInput(label, def string, key ...string) string

PasswordInput adds a single-line text field whose contents are masked in the browser and returns its current value, mirroring Streamlit's st.text_input(type="password"). def is the initial value.

func (*Container) PieChart added in v0.2.0

func (c *Container) PieChart(values []float64, labels []string)

PieChart adds a pie chart. values gives each slice's magnitude and the optional labels name the slices in order. Non-positive totals render an empty chart.

func (*Container) Pills added in v0.3.0

func (c *Container) Pills(label string, options []string, key ...string) []string

Pills adds a row of selectable "pill" chips allowing multiple selections and returns the currently selected options, mirroring Streamlit's st.pills. Selections not present in options are dropped. An optional stable key may be supplied as the final argument.

func (*Container) Popover added in v0.2.0

func (c *Container) Popover(label string) *Container

Popover adds a button that reveals a small floating panel when clicked and returns a container for the panel's body. The panel is toggled in the browser without rerunning the app, making it a convenient home for extra controls or help text.

func (*Container) PrimaryButton added in v0.3.0

func (c *Container) PrimaryButton(label string, key ...string) bool

PrimaryButton adds an emphasised call-to-action button and returns true on the single run triggered by a click, mirroring Streamlit's st.button(type= "primary"). It behaves exactly like Container.Button but is styled as the page's primary action.

func (*Container) Progress

func (c *Container) Progress(value float64)

Progress adds a progress bar. value is a fraction in the range [0, 1] and is clamped to that range. Alongside the clamped fraction the element records an integer "percent" in [0, 100] computed as int(value*100), matching the 0–100 completion value Streamlit's st.progress reports.

func (*Container) Radio

func (c *Container) Radio(label string, options []string, key ...string) string

Radio adds a group of mutually exclusive radio options and returns the selected option. Behaves like Container.SelectBox for defaults.

func (*Container) ScatterChart added in v0.2.0

func (c *Container) ScatterChart(xs, ys []float64)

ScatterChart adds a scatter plot of the paired xs and ys values, rendered to inline SVG on the server. Points beyond the shorter of the two slices are ignored. Unlike the line/bar/area charts, the axes are scaled to the data rather than anchored at zero.

func (*Container) SegmentedControl added in v0.3.0

func (c *Container) SegmentedControl(label string, options []string, key ...string) string

SegmentedControl adds a single-choice segmented button group and returns the selected option, mirroring Streamlit's st.segmented_control. The first option is selected by default; if options is empty the empty string is returned.

func (*Container) SelectBox

func (c *Container) SelectBox(label string, options []string, key ...string) string

SelectBox adds a drop-down of options and returns the selected option. The first option is selected by default; if options is empty the empty string is returned.

func (*Container) SelectSlider added in v0.2.0

func (c *Container) SelectSlider(label string, options []string, key ...string) string

SelectSlider adds a slider that moves across a set of discrete options and returns the currently selected option. The first option is selected by default. If options is empty the empty string is returned.

func (*Container) SelectSliderRange added in v0.3.0

func (c *Container) SelectSliderRange(label string, options []string, key ...string) (string, string)

SelectSliderRange adds a slider that selects a contiguous range across a set of discrete options and returns the currently selected low and high options, mirroring Streamlit's st.select_slider used with a tuple default. By default the full range (first to last option) is selected. The returned pair is ordered by position in options. If options is empty two empty strings are returned.

func (*Container) Slider

func (c *Container) Slider(label string, min, max, def, step float64, key ...string) float64

Slider adds a numeric slider bounded by min and max, initialised to def, and returns its current value. step controls the increment; if step is zero a sensible default of (max-min)/100 is used.

If min and max are supplied out of order they are swapped. When the current value falls outside [min, max] the bounds are widened to include it rather than the value being clamped, matching Streamlit's st.slider — which adjusts the range to fit an out-of-range default instead of moving the value. As a result the returned value is always exactly the resolved value, and min/max on the element may differ from the arguments.

func (*Container) SliderRange added in v0.3.0

func (c *Container) SliderRange(label string, min, max, low, high, step float64, key ...string) (float64, float64)

SliderRange adds a two-handle range slider bounded by min and max and returns the currently selected low and high values, mirroring Streamlit's st.slider used with a tuple default. low and high are the initial handle positions; both returned values are clamped to [min, max] and the lower is always returned first. step controls the increment; a non-positive step defaults to (max-min)/100.

func (*Container) Snow added in v0.3.0

func (c *Container) Snow()

Snow triggers the falling-snow animation, mirroring Streamlit's st.snow. It adds a one-shot effect element to the page.

func (*Container) Spinner

func (c *Container) Spinner(label string)

Spinner adds a spinner with a label. In this synchronous MVP the spinner is primarily decorative: the element tree is delivered only after the run completes, so a spinner marks a region that performed work rather than animating during it.

func (*Container) Status added in v0.2.0

func (c *Container) Status(label string, state ...string) *Container

Status adds a collapsible status box with a label and a visual state and returns a container for its body. The optional state is one of "running" (default), "complete", or "error"; it selects the icon shown beside the label. Because the app reruns top to bottom, updating a status is simply a matter of calling Status again with a new state on the next run.

st := s.Status("Crunching numbers…", "running")
st.Write("step 1 done")

func (*Container) Subheader

func (c *Container) Subheader(text string)

Subheader adds a smaller section header.

func (*Container) Success

func (c *Container) Success(text string)

Success adds a green success message box.

func (*Container) Table

func (c *Container) Table(data any, caption ...string)

Table renders tabular data. It accepts:

  • [][]string, where the first row is treated as the header;
  • a slice of structs, where exported field names become the header and each element becomes a row;
  • a single struct, rendered as a one-row table.

An optional caption is shown beneath the table. Anything unsupported falls back to a JSON view.

func (*Container) Tabs added in v0.2.0

func (c *Container) Tabs(labels []string) []*Container

Tabs adds a tabbed region with one tab per label and returns a container for each tab's body, in the same order as labels. Switching between tabs happens entirely in the browser and does not rerun the app. If labels is empty a single unnamed tab is created.

tabs := s.Tabs([]string{"Chart", "Data"})
tabs[0].LineChart(series)
tabs[1].DataFrame(rows)

func (*Container) Text

func (c *Container) Text(text string)

Text adds fixed-width, unformatted text.

func (*Container) TextArea

func (c *Container) TextArea(label, def string, key ...string) string

TextArea adds a multi-line text field initialised to def and returns its current value.

func (*Container) TextInput

func (c *Container) TextInput(label, def string, key ...string) string

TextInput adds a single-line text field initialised to def and returns its current value.

func (*Container) TextInputMax added in v0.3.0

func (c *Container) TextInputMax(label, def string, maxChars int, key ...string) string

TextInputMax adds a single-line text field that accepts at most maxChars characters and returns its current value, truncated to maxChars runes, mirroring Streamlit's st.text_input(max_chars=…). A maxChars of zero or less imposes no limit.

func (*Container) TimeInput added in v0.2.0

func (c *Container) TimeInput(label, def string, key ...string) string

TimeInput adds a time-of-day field and returns the selected time as a 24-hour "15:04" string. def is the initial value and may be empty.

func (*Container) Title

func (c *Container) Title(text string)

Title adds a top-level page title.

func (*Container) Toast added in v0.3.0

func (c *Container) Toast(message string, icon ...string)

Toast adds a transient notification message, mirroring Streamlit's st.toast. An optional leading icon (typically an emoji) may be supplied as the second argument.

func (*Container) Toggle added in v0.2.0

func (c *Container) Toggle(label string, def bool, key ...string) bool

Toggle adds an on/off switch initialised to def and returns its current state. It behaves like Container.Checkbox but renders as a sliding toggle.

func (*Container) Video added in v0.2.0

func (c *Container) Video(src any)

Video adds a video player. src may be a URL string or raw video bytes (for example MP4), which are embedded as a data URI.

func (*Container) Warning

func (c *Container) Warning(text string)

Warning adds a yellow warning message box.

func (*Container) Write

func (c *Container) Write(args ...any)

Write is the Swiss-army display method, mirroring Streamlit's st.write. It inspects each argument's dynamic type and dispatches to the most appropriate specialised renderer:

Passing multiple arguments renders each in turn.

type Element

type Element struct {
	// Type identifies how the frontend should render the node, for example
	// "title", "slider" or "columns".
	Type string `json:"type"`
	// Key is the stable widget identity. It is empty for non-widget
	// elements. Widget interaction events reference this value.
	Key string `json:"key,omitempty"`
	// Props holds the element's rendered attributes (labels, values, SVG
	// markup, table rows, and so on).
	Props map[string]any `json:"props,omitempty"`
	// Children holds nested elements for layout containers.
	Children []*Element `json:"children,omitempty"`
}

Element is a single node in the page's element tree.

The element tree is the serializable description of everything the app wants the browser to display for the current run. Each call such as Container.Title or Container.Slider appends one Element to the tree. Elements are marshalled to JSON and shipped to the embedded frontend, which renders them and, for widgets, sends interaction events back to the server.

An Element carries a Type (interpreted by the frontend renderer), an arbitrary Props bag, an optional Key (stable identity used for widgets), and nested Children (used by layout containers such as columns and expanders).

type MapPoint added in v0.2.0

type MapPoint struct {
	Lat float64
	Lng float64
}

MapPoint is a single latitude/longitude coordinate plotted by Container.Map. Latitude is in the range [-90, 90] and longitude in [-180, 180].

type Options added in v0.4.0

type Options struct {
	// MaxSessions caps concurrently retained sessions; <= 0 selects
	// [DefaultMaxSessions].
	MaxSessions int
	// SessionIdleTimeout is how long an idle session is retained; <= 0
	// selects [DefaultSessionIdleTimeout].
	SessionIdleTimeout time.Duration
	// MaxUploadBytes caps a single upload request body; <= 0 selects
	// [DefaultMaxUploadBytes].
	MaxUploadBytes int64
	// MaxRequestBytes caps a single /api/run request body; <= 0 selects
	// [DefaultMaxRequestBytes].
	MaxRequestBytes int64
	// MaxWidgetEntries caps how many widget-state entries one session
	// retains; <= 0 selects [DefaultMaxWidgetEntries].
	MaxWidgetEntries int
	// MaxWidgetStateBytes caps the total size of one session's widget-state
	// values; <= 0 selects [DefaultMaxWidgetStateBytes].
	MaxWidgetStateBytes int64
	// AllowedOrigins lists extra browser origins ("https://app.example.com")
	// permitted to drive the app. Same-origin requests are always allowed;
	// requests carrying any other Origin are rejected with 403. Leave it nil
	// unless the app is deliberately embedded in another site.
	AllowedOrigins []string
	// AllowAllOrigins disables origin checking entirely. Only set it when the
	// app is deliberately public and stateless — with it on, any web page a
	// user visits can drive their session (cross-site request forgery).
	AllowAllOrigins bool
}

Options configures the HTTP surface returned by HandlerWithOptions. The zero Options is valid and selects the documented default for every field.

type Session

type Session struct {

	// State is the persistent per-session key/value store.
	State *State
	// contains filtered or unexported fields
}

Session represents a single browser connection to the app. It embeds the root Container, so every display and widget method may be called directly on the session (for example s.Title or s.Slider). A fresh Session is created for each new browser and reused for every rerun triggered by that browser.

The app function receives a *Session and builds the page by calling methods on it. On each run the element tree is rebuilt from scratch while widget values and State persist, faithfully reproducing Streamlit's rerun-on-interaction model.

Example

ExampleSession demonstrates building a page and inspecting the resulting element tree without an HTTP server. Rendering an app function against a session produces a deterministic tree that can be walked and asserted on.

app := func(s *Session) {
	s.Title("Report")
	n := s.Slider("Count", 0, 10, 3, 1)
	s.Metric("Count", fmt.Sprintf("%.0f", n), "+1")
}

s := newSession()
tree := s.run(app)

// The main region holds the three elements in call order.
main := tree.Children[1]
for _, el := range main.Children {
	fmt.Println(el.Type)
}
Output:
title
slider
metric
Example (CacheResource)

ExampleSession_cacheResource shows the @st.cache_resource analogue: a singleton built once and shared by every session, unlike Cache which holds data and can expire.

CacheResourceClear()

builds := 0
open := func() any {
	builds++
	return "connection"
}

a, b := newSession(), newSession()
fmt.Println(a.CacheResource("db", open))
fmt.Println(b.CacheResource("db", open))
fmt.Println("builds:", builds)
Output:
connection
connection
builds: 1
Example (Rerun)

ExampleSession_rerun shows st.rerun's control flow: the run is abandoned at the call and the app executes again from the top, so the second pass sees the state written just before it and the discarded elements never reach the page.

app := func(s *Session) {
	if !s.State.GetBool("ready", false) {
		s.Text("loading…") // discarded: this pass is thrown away
		s.State.Set("ready", true)
		s.Rerun()
	}
	s.Title("Dashboard")
}

s := newSession()
tree := s.run(app)

main := tree.Children[1]
fmt.Println("elements:", len(main.Children))
fmt.Println("first:", main.Children[0].Type)
Output:
elements: 1
first: title
Example (State)

ExampleSession_state shows the two lifetimes an app has to reason about. State survives every rerun; a widget's value survives only as long as the app keeps rendering that widget.

app := func(s *Session) {
	s.State.SetDefault("runs", 0)
	s.State.Set("runs", s.State.GetInt("runs", 0)+1)
	s.TextInput("Name", "anon", "name")
}

s := newSession()
s.run(app)
s.widgets["name"] = "ada" // stand-in for a browser interaction
tree := s.run(app)

fmt.Println("runs:", s.State.GetInt("runs", 0))
fmt.Println("name:", tree.Children[1].Children[0].Props["value"])
fmt.Println("keys:", s.State.Keys())
Output:
runs: 2
name: ada
keys: [runs]
Example (Stop)

ExampleSession_stop shows st.stop: elements added before the call stay on the page and nothing after it runs.

app := func(s *Session) {
	s.Title("Private area")
	if !s.State.GetBool("authenticated", false) {
		s.Error("Please log in")
		s.Stop()
	}
	s.Text("secrets")
}

s := newSession()
main := s.run(app).Children[1]
for _, el := range main.Children {
	fmt.Println(el.Type)
}
Output:
title
alert

func (*Session) Cache added in v0.2.0

func (s *Session) Cache(key string, compute func() any, ttl ...time.Duration) any

Cache returns the value memoised under key, computing it with compute on the first call (or after the entry has expired) and returning the stored value on subsequent calls. The cache is process-wide and shared across sessions, so an expensive computation runs once and is reused by every rerun and every browser, mirroring Streamlit's st.cache_data.

An optional time-to-live may be supplied as the final argument; a positive TTL causes the entry to be recomputed once it has aged past the duration. A zero or omitted TTL caches for the lifetime of the process.

rows := s.Cache("report", func() any { return loadReport() }, time.Minute)
report := rows.([]Row)

Concurrent callers asking for the same missing key do not each run compute: the first caller computes while the others wait for its result. The table holds at most DefaultMaxCacheEntries entries (see CacheSetMaxEntries); when it is full the entry inserted longest ago is evicted. Derive keys that include everything the computation depends on — this port takes an explicit key rather than hashing the arguments the way Python's decorator does.

func (*Session) CacheResource added in v0.4.0

func (s *Session) CacheResource(key string, create func() any) any

CacheResource returns the singleton registered under key, creating it with create on the first call, mirroring Streamlit's @st.cache_resource. Use it for objects that are expensive to build and safe to share — database handles, model weights, clients — rather than for data.

Unlike Session.Cache a resource has no TTL and is never evicted, so create runs exactly once per key for the lifetime of the process. create must return a value that is safe for concurrent use, because every session shares it.

db := s.CacheResource("db", func() any { return mustOpenDB() }).(*sql.DB)

func (*Session) ID

func (s *Session) ID() string

ID returns the session's opaque identifier.

func (*Session) Rerun added in v0.4.0

func (s *Session) Rerun()

Rerun abandons the current run and immediately re-executes the app function from the top, mirroring Streamlit's st.rerun. Every element added so far is discarded; State and widget values persist, so the fresh run observes any change made before the call.

It is the escape hatch for "I have just mutated state that earlier code already rendered" — the canonical example being a login form that must repaint the whole page once authentication succeeds:

if s.Button("Log in") {
	s.State.Set("user", name)
	s.Rerun() // repaint the page as the logged-in user
}

Like Session.Stop it is implemented by panicking with an internal sentinel and so must be called from within the app function, not a separate goroutine. A chain of reruns within a single request is capped (see maxRerunChain); an app that calls Rerun unconditionally therefore terminates with the tree from the final permitted run instead of hanging.

func (*Session) SetPageConfig added in v0.3.0

func (s *Session) SetPageConfig(title, icon string)

SetPageConfig sets page-level metadata for the app, mirroring Streamlit's st.set_page_config. title is the browser tab title and icon is an optional favicon (typically an emoji). The values are attached to the root of the element tree. Call it once, at the top of the app function.

func (*Session) Sidebar

func (s *Session) Sidebar() *Container

Sidebar returns the container for the app's sidebar region. Elements added to it render in a fixed panel beside the main content.

func (*Session) Stop added in v0.3.0

func (s *Session) Stop()

Stop immediately halts execution of the current run of the app function, mirroring Streamlit's st.stop. Elements added before the call remain on the page; nothing after it runs. It is implemented by panicking with an internal sentinel that the run loop recovers, so it must be called from within the app function (not from a separate goroutine).

if !authenticated {
	s.Error("Please log in")
	s.Stop() // the rest of the app does not run
}

type State

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

State is a per-session key/value store that persists across reruns of the app function. It is the Go analogue of Streamlit's st.session_state and is a convenient place to keep data (counters, accumulated history, cached computations) that must survive the top-to-bottom re-execution of the app.

State is safe to use only from within a single run of the app function; the server serialises runs of a given session, so no additional locking is required by app code.

func (*State) Clear added in v0.4.0

func (s *State) Clear()

Clear removes every key from the store.

func (*State) Delete

func (s *State) Delete(key string)

Delete removes key from the store.

func (*State) Get

func (s *State) Get(key string) (any, bool)

Get returns the value stored under key and whether it was present.

func (*State) GetBool added in v0.4.0

func (s *State) GetBool(key string, def bool) bool

GetBool returns the bool stored under key, or def if absent or not a bool.

func (*State) GetFloat

func (s *State) GetFloat(key string, def float64) float64

GetFloat returns the float64 stored under key, or def if absent or not numeric.

func (*State) GetInt

func (s *State) GetInt(key string, def int) int

GetInt returns the int stored under key, or def if absent or not numeric.

func (*State) GetString

func (s *State) GetString(key, def string) string

GetString returns the string stored under key, or def if absent or not a string.

func (*State) Has added in v0.4.0

func (s *State) Has(key string) bool

Has reports whether key is present, mirroring `key in st.session_state`.

func (*State) Keys added in v0.4.0

func (s *State) Keys() []string

Keys returns the store's keys in ascending lexical order. The order is sorted rather than map order so that iterating state is deterministic across reruns.

func (*State) Len added in v0.4.0

func (s *State) Len() int

Len returns the number of keys held in the store.

func (*State) Set

func (s *State) Set(key string, value any)

Set stores value under key.

func (*State) SetDefault added in v0.4.0

func (s *State) SetDefault(key string, value any) bool

SetDefault stores value under key only if the key is absent and reports whether it was stored. It is the analogue of Streamlit's common `if "k" not in st.session_state: st.session_state.k = v` idiom, which is how per-session state is seeded on the first of many reruns.

type UploadedFile added in v0.2.0

type UploadedFile struct {
	// Name is the client-supplied filename.
	Name string
	// Size is the length of Data in bytes.
	Size int
	// Data is the file's raw content.
	Data []byte
}

UploadedFile is a single file received from a Container.FileUploader. Data holds the raw bytes uploaded by the browser.

Jump to

Keyboard shortcuts

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