MyGo
Form

Containers

Form

Labeled controls with descriptions and errors.

Form

A ui.Field labels the control its function builds: the label names the control for assistive technology, and a click on it focuses the control, or clicks a check box, a switch or a radio button. Description and Error add texts below the control, which assistive technology reads with it; an error also marks the control's value invalid, and a text input draws its border in the theme's Danger color. An empty error leaves the control valid:

var invalid string
if app.email != "" && !strings.Contains(app.email, "@") {
	invalid = "Enter an email address."
}
ui.Field(c, "Email", func() {
	ui.TextInput(c, &app.email)
}).Description("For receipts.").Error(invalid)

The control is the first element the function builds that takes the focus, or a group of them, such as a radio group.

Forms

A field's label sits above its control, as on the web. In a ui.Form, the labels of its fields sit in a column of their own beside the controls, as in macOS's forms: aligned to the right, as wide as the widest, and level with the first line of text of their control, or centered on a control without text, such as a switch.

ui.Form(c, func() {
	ui.Field(c, "Name", func() { ui.TextInput(c, &app.name) })
	ui.Field(c, "Plan", func() { ui.Select(c, &app.plan, plans) })
	ui.Field(c, "Sound", func() { ui.Switch(c, &app.sound) })
})

Fieldsets

A ui.Fieldset groups fields under a legend, which names the group; their labels line up with the form's others, and Disabled disables them all:

ui.Form(c, func() {
	ui.Field(c, "Name", func() { ui.TextInput(c, &app.name) })
	ui.Fieldset(c, "Notifications", func() {
		ui.Field(c, "Email", func() { ui.Checkbox(c, &app.mail, "Weekly summary") })
		ui.Field(c, "Sound", func() { ui.Switch(c, &app.sound) })
	}).Disabled(!app.signedIn)
})

A control with a name of its own, as a check box with its text, keeps it, and the field's label names the group around them.

Labels of your own

A view that draws a control's caption itself, as a text above an input in a component's own layout, ties the two with LabelledBy, as a <label for> does on the web: the text names the control for assistive technology, in place of the control's Label, and a click on it focuses the control, or clicks a check box, a switch or a radio button, as a field's label does. The label can come before the control or after it:

caption := ui.Text(c, "Card number").TextColor(t.TextMuted)
ui.TextInput(c, &app.card).LabelledBy(caption)

ui.Row(c).Gap(8).Children(func() {
	agree := ui.Checkbox(c, &app.agree, "")
	agree.LabelledBy(ui.Text(c, "I agree to the terms"))
})

Hints and errors of your own

A hint or an error message the view draws as an element of its own, away from the field's Description and Error, reaches assistive technology with DescribedBy and ErrorMessage, as aria-describedby and aria-errormessage. Invalid marks a value as not valid without a message, as a required field the user left empty, whose message shows once the form is submitted:

hint := ui.Text(c, "As printed on the card").TextColor(t.TextMuted)
ui.Field(c, "Name", func() {
	ui.TextInput(c, &app.name).Invalid(app.nameTouched && app.name == "")
}).DescribedBy(hint)

On a field, they go to its control, as Description and Error do (Accessibility).

Accessibility

Assistive technology reads a control by its field's label, with the description and the error after it, and the value invalid while there is an error, or while Invalid says so; a fieldset is a group named by its legend.