Home › Concepts
Context
Flux.context(default) passes shared values (themes, services, or active user state) down a component tree without threading props through every intermediate function.
local ThemeContext = Flux.context({
background = Color3.fromRGB(20, 20, 24),
text = Color3.fromRGB(235, 235, 235),
accent = Color3.fromRGB(120, 170, 255),
})
local function ThemedButton(label: string)
local theme = ThemeContext:get()
return Flux.new "TextButton" {
BackgroundColor3 = theme.accent,
TextColor3 = theme.text,
Text = label,
}
end
local button = ThemeContext:provide({
background = Color3.fromRGB(40, 20, 60),
text = Color3.fromRGB(255, 235, 245),
accent = Color3.fromRGB(255, 120, 200),
}, function()
return ThemedButton("Play")
end)Creating a Context
Call Flux.context(default) with a fallback value returned whenever no provide is active. The context value can be a plain table, a primitive, a Signal, or a Store.
Providing and Reading
context:provide(value, fn)runsfnwith this context set tovalue, then restores the previous value whenfnreturns (or throws).context:get()returns the value from the innermost activeprovide, orcontext.defaultif none is active.
Every Computed, Effect, Scope, property binding, and event handler in Flux.new / Flux.edit remembers the context values active where it was created, so later re-runs keep reading the provided value:
local Theme = Flux.context("dark")
local count = Flux.signal(0)
local label = Theme:provide("light", function()
return Flux.new "TextLabel" {
-- Re-runs when `count` changes and still reads `"light"`
Text = function()
return `[{Theme:get()}] Clicks: {count()}`
end,
}
end)Reactive State in Context
A context slot itself isn't a reactive node. Calling provide sets which value a subtree receives when it mounts. When the provided value needs to change over time, pass a Signal or Store as the context value:
local AccentContext = Flux.context(Flux.signal(Color3.fromRGB(120, 170, 255)))
local function ActionButton()
local accent = AccentContext:get() -- Node<Color3>
return Flux.new "TextButton" {
BackgroundColor3 = accent, -- bound reactively
Text = "Confirm",
}
endDeferred Code
Computeds, Effects, Scopes, and event handlers declared inside Flux.new / Flux.edit capture the active context automatically.
When you register a callback outside Flux (such as a manual RBXScriptSignal:Connect, a task.delay timer, or a callback handed to a third-party module), wrap it with Flux.bindContext(fn) (or Flux.withOwner) so it runs with the context active where it was wrapped:
local onDelayedOpen = Flux.bindContext(function()
-- Reads the ThemeContext value that was active when `onDelayedOpen` was created
local theme = ThemeContext:get()
openDialogWithTheme(theme)
end)
task.delay(2, onDelayedOpen)