Button and Switch
Pointer activation, Enter and Space use the same callback. Disabled controls block activation. A switch reports its checked state to assistive technology. Supply your own layout, hover/press styles and content.
Switch API →COMPONENTS / BEHAVIOR WITHOUT A VISUAL THEME
Controlled buttons, switches, sliders, tabs, dialogs and scroll areas. The same components below take on two different appearances, with independent state and focus.
Preparing the controls...
Initializing renderer
Preparing the controls...
Initializing renderer
ONE CONTRACT / YOUR DESIGN
These are React components built from the four primitives. They do not install a theme or keep a second copy of your game state. A change callback asks the owner to update the next prop. Plain text belongs inside Text; use children or render functions to compose any appearance.
import { useState } from 'react';
import { Button, Switch, Slider, Text, View } from 'ludic-canvas';
function Settings() {
const [hints, setHints] = useState(true);
const [volume, setVolume] = useState(0.5);
return <View style={{ gap: 16 }}>
<Switch label="Navigation hints" checked={hints}
onCheckedChange={setHints} style={{ padding: 12 }}>
<Text>{hints ? 'Hints on' : 'Hints off'}</Text>
</Switch>
<Slider label="Volume" value={volume} onValueChange={setVolume}
style={{ width: 240, height: 44, justifyContent: 'center' }}>
{({ ratio }) => <View fill={ratio} fillColor="#a6e5cf"
style={{ height: 6, background: '#28483f' }} />}
</Slider>
<Button label="Save settings" onPress={() => save({ hints, volume })}
style={{ padding: 16, background: '#28483f' }}>
<Text>Save settings</Text>
</Button>
</View>;
}Pointer activation, Enter and Space use the same callback. Disabled controls block activation. A switch reports its checked state to assistive technology. Supply your own layout, hover/press styles and content.
Switch API →A horizontal slider owns primary-pointer capture, cancellation, min/max clamping and step snapping. Arrows change one step, Page Up/Down ten steps, and Home/End the endpoints. Its render function receives value, ratio and dragging. Cancellation never calls onValueCommit.
Tabs groups controlled Tab components into one keyboard Tab stop. Arrows activate and focus adjacent enabled entries; Home/End jump to the ends. Choose horizontal or vertical navigation. Render the corresponding content from your controlled value; this component does not create tab panels.
Tabs API →The owner controls open. While visible, the topmost dialog isolates background input, traps Tab and requests Escape dismissal. Closing restores focus. Style the scrim and compose a panel and close button yourself. Disable Escape dismissal for a mandatory briefing or result screen.
A named vertical scroll region with wheel/touch scrolling and automatic reveal of focused controls. Give it a constrained height and content that can exceed it. Rendering remains eager; this is not a virtualized list.
ScrollArea API →Components can focus a stable control identifier through their owning root. Every createUI().render() supplies its own React context. The two previews deliberately reuse control identifiers while retaining separate focus and resource ownership.
const [open, setOpen] = useState(false);
<Dialog label="Pause menu" open={open} onOpenChange={setOpen}
style={{ background: '#10201be6', justifyContent: 'center', alignItems: 'center' }}>
<View style={{ width: 280, padding: 24, gap: 16, background: '#28483f' }}>
<Text>Take a moment.</Text>
<Button label="Resume game" onPress={() => setOpen(false)}>
<Text>Resume</Text>
</Button>
</View>
</Dialog>The dialog manages UI input. Your application decides whether opening it also pauses simulation, audio or networking. Set comfortable touch targets, provide labels, and test your finished interface with real assistive technology. Static text still has the documented accessibility and typography limits.
Both playable examples use these components with their own design systems. The initializer gives you a smaller starting point.