Hudini Radio + RadioGroup

Single-selection form control. RadioGroup manages the 'only one selected' invariant via a factory; individual Radios are free to be positioned anywhere in the scene.

Radio + RadioGroup

Two components that work together. Radio is a single-selection form control — same contract as Checkbox (uncontrolled state, getValue(), disabled, readOnly, custom icon), but click always selects and never deselects (matches native <input type="radio">).

RadioGroup is a stateless controller — no visual, just a factory. Call group.createRadio() and place the returned Radios anywhere you want. The group enforces "only one selected" internally.

Recommended: use RadioGroup whenever you have 2+ related radios. Standalone Radio is supported but you own the "only one" logic manually.

Features

  • đŸŽ¯ Layout-free grouping: createRadio() returns a Radio you can drop anywhere — Stack, Card, scattered HUD positions
  • 🔒 "Only one" invariant guaranteed by the group; no hidden global state, no scene-wide registry
  • 💚 Custom icon per Radio (default 'circle', or use 'heart', 'star', 'skull', ...)
  • 🎨 Group-level defaults (color, size, icon) inherited by every Radio, overridable per Radio
  • ✨ Pop animation on the inner icon — scale + fade in with Back.easeOut
  • 📋 Form-ready: group.getValue() returns the selected string

RadioGroup props

  • scene - Phaser scene shared by all radios in the group
  • name - Form field name, passed to onChange
  • value - Initially selected value
  • disabled, readOnly - Apply to every radio in the group
  • color, icon, iconColor, size, borderRadius, labelColor - Defaults for every Radio created by this group
  • onChange - (value, name?) => void

RadioGroup methods

  • createRadio(params) - Factory. Same params as Radio, but the group manages checked and onChange
  • setValue(v) / getValue() - Programmatic selection
  • disable() / enable() / setDisabled(v) / isDisabled()
  • setReadOnly(v) / isReadOnly()
  • onChange(cb) - Replace the callback
  • destroy() - Clear the group's registry (does not destroy the Radios themselves)

Live Example

Loading game...

Usage Example

import Phaser from 'phaser';
import {
    createTheme,
    HUDINI_KEY,
    HudiniPlugin,
    withHudini,
    RadioGroup,
    Stack,
} from 'hudini';

class DifficultyScene extends Phaser.Scene {
    create(): void {
        // 1. Create the group first — no visual.
        const group = new RadioGroup({
            scene: this,
            name: 'difficulty',
            value: 'normal',
            color: 'blue-500',
            onChange: (value) => {
                console.log('selected:', value);
            },
        });

        // 2. Create Radios via the factory. Place them anywhere.
        const easy   = group.createRadio({ x: 0, y: 0, value: 'easy',   label: 'Easy' });
        const normal = group.createRadio({ x: 0, y: 0, value: 'normal', label: 'Normal' });
        const hard   = group.createRadio({ x: 0, y: 0, value: 'hard',   label: 'Hard' });

        // 3. Lay them out — Stack (or wherever you want).
        const layout = new Stack({
            scene: this, x: 400, y: 300,
            direction: 'column',
            gap: 12,
            children: [easy, normal, hard],
        });
        this.add.existing(layout);

        // Read the current value later (form-style):
        console.log(group.getValue()); // 'normal'
    }
}