Composition API
Save a name for all your tabs, click a counter that adds one more each time, and vote for an animal with every other visitor. The page and its vote widgets are classes built with #[Signal], #[Signal(Scope::SESSION)], #[Signal(Scope::GLOBAL)], #[Persist] and #[Action].
data-bind. Each browser tab has its own isolated copy.totalClicks counter increments for all users simultaneously, regardless of which tab triggered it.name: argument overrides the URL slug: resetTab is exposed as /_action/reset-tab.VoteWidget is mounted three times with #[Signal(Scope::GLOBAL)] votes. SignalFactory puts the component namespace into scoped signal IDs, giving each animal its own global counter: global_cats_votes____kn, global_dogs_votes____kn, global_parrots_votes____kn.Session Name Signal(SESSION)
Hello, Anonymous!
Open another tab: saving here updates the greeting in both tabs.
Counter Persist
Count: 0
Each click adds +1, +2, +3… The multiplier is a server-only #[Persist] property: it survives between action calls but is never sent to the client.
Global Clicks Signal(GLOBAL)
Total clicks (all users): 0
Every action on this page increments this counter. Open two browser sessions: clicking in either updates the counter in both.
Vote Widgets Component × 3
Same VoteWidget class mounted three times. Signals auto-namespace: cats.votes, dogs.votes, parrots.votes. Clicking one widget never affects the others.
0
0
0
Signals
nameInput
string tab scope initial: empty string Client-writable input bound via data-bind. Holds the typed name until saveName is called.
name
string session scope initial: "Anonymous" Promoted from nameInput by saveName. SESSION scope auto-broadcasts to all tabs of this session.
count
int tab scope initial: 0 Per-tab counter. Each click adds the current multiplier: grows +1, +2, +3… proving #[Persist] survives between actions.
multiplier
int server only initial: 1 Server-only instance property (not a signal). Invisible to the client. Grows by 1 on each increment call.
totalClicks
int global scope initial: 0 Counts every action call by every user. GLOBAL scope auto-broadcasts to all connected sessions.
votes (VoteWidget)
int global scope initial: 0 Per-animal vote counter. SignalFactory namespaces the ID: global_cats_votes____kn, global_dogs_votes____kn, global_parrots_votes____kn. Shared across all users, and back to 0 once no context uses the GLOBAL scope.
Actions
increment
Adds multiplier to count, then bumps both multiplier and totalClicks.
reset-tab
Resets count and multiplier for this tab only. Custom slug via #[Action(name: 'reset-tab')].
saveName
Copies nameInput to name (SESSION signal). Auto-broadcasts to all of this user's tabs.
vote
VoteWidget action. Independent per instance: cats.vote, dogs.vote, parrots.vote. Every user sees the same votes.
Views
composition.html.twig
Page shell. Renders all signals and three embedded VoteWidget components.
composition_vote.html.twig
VoteWidget component template. Uses the auto-namespaced votes signal and vote action.