io.group

Several fields, one Continue.

io.group puts several io calls on one form. The person fills them in and presses Continue once. The handler gets all the values together, each typed by its key.

The simplest one

The whole action file, and roughly what your team sees when it runs.

src/actions/accounts/createAccountAction.ts
import { app } from '../../app';
export const createAccountAction = app.defineAction({
name: 'Create account',
handler: async ({ io }) => {
const { company, email, note } = await io.group({
company: io.input.text('Company name'),
email: io.input.email('Owner email'),
note: io.input.textarea('Note for the team'),
});
return `${company} has an account.`;
},
});
The code. One call in an action, the whole file.
tools.example.com/actions/accounts/create_account

Create account

Company nameNorthwind Traders
Owner emailana@northwind.example
Note for the teamMoving over from the old billing system in November.
Continue
In the browser. Roughly what your team sees. Your theme decides the details.

What you can set

The settings you will reach for most, each with the line of code that turns it on.

const { company, note } = await io.group({

One form, one Continue. Every field of the group sits on one screen. The person answers them all at once.

company: io.input.text('Company name'),

No await inside. Pass the io calls without await. Inside io.group a call only describes its field.

io.group({ company, endsAt, note })

In the order of the keys. The fields appear as the keys of the object go. Only an object is accepted, not an array.

// company: string, endsAt: DateTime

Typed per key. Each key holds what its io call returns. A text field gives a string, a date field a luxon DateTime.

email: io.input.email('Owner email'),

All errors at once. The server checks every field when the form is sent. Each error shows under its own field.

.validate(({ startsAt, endsAt }) =>

A check across fields. Chain .validate() to the group. Its message shows above Continue, and it runs on the server.

note: io.input.textarea('Note').optional(),

Optional fields. Chain .optional() to a field. It can stay empty, and its key holds undefined.

summary: io.display.metadata(null, totals),

Totals next to inputs. A display component can sit between the fields. It shows something and answers undefined.

await io.group({})

Nothing to register. io.group is part of awaitio. An empty group shows just the Continue button.

Write your first tool today.

An async function, a few await calls, and the form is in the browser.

AwaitIO is free for small teams, made possible by companies and people who sponsor it.