Topics let multiple WASM components on the same page share reactive state. Think of them as Gothic's version of React's useContext. One component publishes a value and every component subscribed to that field reacts automatically.
A topic is just a struct declared in src/topics/. Each field becomes an *ObservableField[T] with .Get(), .Set(), and .Peek() methods. Pass any field to Observe as a dependency and your callback re-runs only when that field changes.
Important: You must dot-import pkg/wasm (import . "github.com/felipegenef/gothicframework/v2/pkg/wasm") for use these helpers, otherwise you will get a tinygo compile error.
Note: the topic manager component must be mounted on the page before any component that subscribes to it. Mount it once at the top of your page template.
Create a file in src/topics/ and call CreateTopic. Gothic generates a subscriber function and a mount component named Add<Name>Topic() for you.
// src/topics/app_topic.go
package gothicwasm
import . "github.com/felipegenef/gothicframework/v2/pkg/wasm"
type App struct {
Count int
Theme string
Label string
}
var _ = CreateTopic (App{}, TopicConfig{
Name : "app" ,
Compression : BROTLI,
SubscriberFnName : "AppTopic" ,
ComponentFnName : "AddAppTopic" ,
}) Mount AddAppTopic() once on the page. Then any component can grab the topic with AppTopic() and call .Set() on a field to publish an update. Use .Peek() when you need the current value without subscribing.
// page template, mount the manager once
templ Home () {
@ AddAppTopic ()
@ Counter ()
@ ThemeSwitcher ()
}
// writer component, publish a single field
ClientSideState : func () {
topic := AppTopic ()
CreateWasmFunc ( "increment" , func () {
topic.Count.Set(topic.Count.Peek() + 1 )
})
CreateWasmFunc ( "toggleTheme" , func () {
if topic.Theme.Peek() == "light" {
topic.Theme.Set( "dark" )
} else {
topic.Theme.Set( "light" )
}
})
} In another component, call AppTopic() to get the same shared instance. Pass a field to Observe as a dependency and the callback re-runs whenever that field changes.
Note: use .Get() inside an Observe callback to subscribe to the field. Use .Peek() to read the value without creating a subscription.
// reader component, reacts to remote changes
ClientSideState : func () {
topic := AppTopic ()
// re-runs only when Count changes, not Theme or Label
Observe ( func () {
SetText ( "count-display" , strconv.Itoa(topic.Count.Get()))
}, topic.Count)
// react to Theme, toggle a class on the root
Observe ( func () {
if topic.Theme.Get() == "dark" {
AddClass ( "root" , "dark" )
} else {
RemoveClass ( "root" , "dark" )
}
}, topic.Theme)
} Liked topics? Next up, pick the right WASM compiler for your route!