Form
The root that makes a screen a native modal form.
Import
import { Form } from '@bedrock-core/ui';
Usage
export default function Settings(): JSX.Element {
return (
<Form onSubmit={({ values }) => apply(values)}>
<Text>{'Settings'}</Text>
<Toggle name={'music'} defaultValue={true} />
<Slider name={'volume'} min={0} max={10} />
<Input name={'nickname'} />
<Form.Button type={'submit'}>{'Save'}</Form.Button>
</Form>
);
}
Form is a host, the way <Screen> and <Container> are. Its presence makes the renderer build one atomic ModalFormData instead of a screen of buttons.
One member: Form.Button
Form.Button, with type submit or exit, is the modal's own submit and dismiss button, and the only member Form has. Every field is a top-level component imported by its own name, and which hosts it works on is its own capability, not something a namespace decides:
import { Button, Dropdown, Form, Input, Option, Select, Slider, Text, Toggle } from '@bedrock-core/ui';
<Toggle>, <Select> and <Option> work on all three hosts and draw differently on each. <Input>, <Slider> and <Dropdown> only work here, because the engine draws no text field, slider or popup anywhere else. See Hosts for the whole table.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
onSubmit | (event: SubmitEvent) => void | — | Called once when the player submits. event.values holds every control's value keyed by its name |
onCancel | (event: UiEvent) => void | — | Called when the player dismisses the modal — the X, Esc, or an exit button |
children | JSX.Node | — | The controls, the decoration and the action buttons, in any order |
Form takes no control props: it is a marker, not a panel. Put a Panel inside it for a background, padding or a direction.
Values arrive once
The native modal is atomic: nothing reaches script while it is open, and every value comes back together on submit.
<Form onSubmit={({ values }) => {
values.music; // boolean
values.volume; // number
values.nickname; // string
}}>
FormValues is Record<string, ModalValue>, where ModalValue is string | number | boolean | undefined. That is why a control here has a name and no onChange — there is nothing to call one from.
A heading is a <Text>: the modal has no title or body prop of its own.
Rules
The build enforces these, with a message naming the fix.
- Exactly one submit. A modal has no built-in submit control, so the screen declares one:
<Form.Button type={'submit'}>. At most one<Form.Button type={'exit'}>beside it. - No nested root. A
<Form>inside a<Form>, or a<Screen>or<Container>inside one, is refused. Mix the two form kinds across separate screens, never nested. - Only what this host can draw. A
<Slot>or a plain press with a handler is refused here by name — a modal draws its typed controls plus its own two actions and nothing else.
Notes
A form cannot be mutated while it is open, so a state change never repaints it. The player sees a new snapshot when they press. State covers what follows from that.
Next steps
- Hosts — what each of the three screens can carry
<Toggle>— the clearest example of one component, three mechanisms- Modal fields — the three that live only here
@bedrock-core/ore-styled— the same controls, themed