Usage
onSubmit that validates and saves. Do not assemble a Drawer, a form layout and a discard prompt in a page. For record detail that is not a form, use DetailDrawer.
Coming from ui-forms DrawerForm? packages/ui/docs/migrating-from-ui-forms.md covers returning Saved or Invalid from a react-hook-form submit, dirty, and resetting the form when the drawer closes.
children are the fields (Field, Fieldset, Select, Combobox, NumberField, TextArea, DateInput, Checkbox (or CheckboxGroup), CheckboxCards, RadioGroup, RadioCards, SegmentedControl, DurationField, FileUpload, or Slider; not a Switch, ADR 0023 decision 5), stacked in a column in the drawer's scrolling body on the FormLayoutStandard layout. Give each field a name: the form data and the unsaved-edits check read named controls only. description and requiredHint sit above the fields; say what the required marker means once, in requiredHint.
Cancel and Submit sit in the drawer footer, outside the scrolling body, so they stay in view. The Submit Button is linked to the form with the native form attribute, so Enter in a single-line field still submits. Focus starts on the first field, not on the header close button.
onSubmit(event) runs on a native submit. The block prevents the native navigation and ignores a repeat submit. Read the values with new FormData(event.currentTarget) and validate there.
FormLayoutDrawerSubmitResult.Saved: the drawer closes.FormLayoutDrawerSubmitResult.Invalid after a failed validation: the drawer stays open. Set invalid (and errorSummary for a form-level message) in the same handler, and focus moves to the first invalid field.Invalid. A rejected promise keeps it open and is not rethrown; report the failure from the handler and pass errorSummary.dirty to say so yourself, for edits the controls do not carry or a control that fills in after open.
summary is one line of status text: a count, a save state, or a validation that spans the form ("Apply at least 1 permission"). It is never a button or a link. At the inline end the actions run tertiary, Cancel, primary. The only tertiary action is Reset, which you pass as reset for a record that has defaults to return to; a blank new record has none. Reset confirms with reset.discard when the form has edits, then returns the fields to the values they had when the form opened and calls reset.onReset so you can clear your own error state. The primary stays enabled for a pristine form, and a failed submit reports through errorSummary (ADR 0023, decisions 12 and 13).
Uncontrolled, the trigger opens the drawer and defaultOpen opens it on mount. Controlled, pass open and onOpenChange. onOpenChange(false, details) is called for a pristine close (close-press or close-request), a discard (close-press) and a saved submit (form-submit); details.cancel() keeps it open. It is not called for a close that is held or confirmed away.
The drawer is always modal: a scrim, a focus trap and an inert page. A backdrop press does not close a modal drawer, so edits cannot be lost to a stray click. A non-modal Drawer closes on an outside press with a light-dismiss that cannot be vetoed, so this block does not offer it.
Load the stylesheets of what it composes: drawer/styles.css, form/styles.css, field/styles.css, button/styles.css, box/styles.css, blocks/form-layout-standard/styles.css, and blocks/confirm-dialog/styles.css with its own list, plus the stylesheet of each control you pass. The block's own blocks/form-layout-drawer/styles.css too.