Forms
Build declarative UI for players without tying plugins to packet details.
In this section
Related section pages:
Server-owned Specs
Forms are server-owned specs with response handlers. They follow Bedrock simple, modal, and custom form shapes while keeping callbacks in core state.
simple-form.go
_, err := playerHandle.SendForm( form.Simple("Kit selector"). Content("Choose a starter kit"). Button("Miner", func(fc form.Context, response form.SimpleResponse) error { playerHandle, ok := ctx.Gameplay().Players().Get(fc.PlayerID) if !ok { return nil } _, err := playerHandle.Inventory().Give(item.New("iron_pickaxe").Stack()) return err }). OnClose(func(fc form.Context, reason form.CloseReason) error { return ctx.Gameplay().SendMessage(gameplay.PlayerMessageRequest{ PlayerID: fc.PlayerID, Text: "No kit selected", }) }))Modal Flow
Modal helpers are useful for confirmation flows. The runtime owns delivery, response routing, and cancellation behavior.
modal.go
form := forms.Modal(). Title("Arena"). Text("Join the active round?"). Submit("Join"). Cancel("Later"). OnSubmit(func(player plugin.PlayerHandle) error { return arena.Join(player.ID()) })return ctx.Forms().Open(playerHandle.ID(), form)Request-style Compatibility
For request-style code, use ctx.Gameplay().SendFormTo(playerID, formRef). Prefer player handles in new code when the player is already resolved.