Form
Our
Form
component provides great user experience to collect some data from a user and submit it for extensions needs.
Items in React can be one of two types: controlled or uncontrolled.
An uncontrolled item is the simpler of the two. It's the closest to a plain HTML input. React puts it on the page, and Raycast keeps track of the rest. Uncontrolled inputs require less code, but make it harder to do certain things.
With a controlled item, YOU explicitly control the
value
that the item displays. You have to write code to respond to changes with defining onChange
callback, store the current value
somewhere, and pass that value back to the item to be displayed. It's a feedback loop with your code in the middle. It's more manual work to wire these up, but they offer the most control.You can take look at these two styles below under each of the supported items.
Before submitting data, it is important to ensure all required form controls are filled out, in the correct format.
In Raycast, validation can be fully controlled from the API. To keep the same behavior as we have natively, the proper way of usage is to validate a
value
in the onBlur
callback, update the error
of the item and keep track of updates with the onChange
callback to drop the error
value.
Keep in mind that if the Form has any errors, the
Action.SubmitForm
onSubmit
callback won't be triggered.import { Form } from "@raycast/api";
import { useState } from "react";
export default function Command() {
const [nameError, setNameError] = useState<string | undefined>();
const [passwordError, setPasswordError] = useState<string | undefined>();
function dropNameErrorIfNeeded() {
if (nameError && nameError.length > 0) {
setNameError(undefined);
}
}
function dropPasswordErrorIfNeeded() {
if (passwordError && passwordError.length > 0) {
setPasswordError(undefined);
}
}
return (
<Form>
<Form.TextField
id="nameField"
title="Full Name"
placeholder="Enter your name"
error={nameError}
onChange={dropNameErrorIfNeeded}
onBlur={(event) => {
if (event.target.value?.length == 0) {
setNameError("The field should't be empty!");
} else {
dropNameErrorIfNeeded();
}
}}
/>
<Form.PasswordField
id="password"
title="New Password"
error={passwordError}
onChange={dropPasswordErrorIfNeeded}
onBlur={(event) => {
const value = event.target.value;
if (value && value.length > 0) {
if (!validatePassword(value)) {
setPasswordError("Password should be at least 8 characters!");
} else {
dropPasswordErrorIfNeeded();
}
} else {
setPasswordError("The field should't be empty!");
}
}}
/>
<Form.TextArea id="bioTextArea" title="Add Bio" placeholder="Describe who you are" />
<Form.DatePicker id="birthDate" title="Date of Birth" />
</Form>
);
}
function validatePassword(value: string): boolean {
return value.length >= 8;
}
Drafts are a mechanism to preserve filled-in inputs (but not yet submitted) when an end-user exits the command. To enable this mechanism, set the
enableDrafts
prop on your Form and populate the initial values of the Form with the top-level prop draftValues
.
- Drafts for forms nested in navigation are not supported yet. In this case, you will see a warning about it.
Uncontrolled Form
Controlled Form
import { Form, ActionPanel, Action, popToRoot, LaunchProps } from "@raycast/api";
interface TodoValues {
title: string;
description?: string;
dueDate?: Date;
}
export default function Command(props: LaunchProps<{ draftValues: TodoValues }>) {
const { draftValues } = props;
return (
<Form
enableDrafts
actions={
<ActionPanel>
<Action.SubmitForm
onSubmit={(values: TodoValues) => {
console.log("onSubmit", values);
popToRoot();
}}
/>
</ActionPanel>
}
>
<Form.TextField id="title" title="Title" defaultValue={draftValues?.title} />
<Form.TextArea id="description" title="Description" defaultValue={draftValues?.description} />
<Form.DatePicker id="dueDate" title="Due Date" defaultValue={draftValues?.dueDate} />
</Form>
);
}
import { Form, ActionPanel, Action, popToRoot, LaunchProps } from "@raycast/api";
import { useState } from "react";
interface TodoValues {
title: string;
description?: string;
dueDate?: Date;
}
export default function Command(props: LaunchProps<{ draftValues: TodoValues }>) {
const { draftValues } = props;
const [title, setTitle] = useState<string>(draftValues?.title || "");
const [description, setDescription] = useState<string>(draftValues?.description || "");
const [dueDate, setDueDate] = useState<Date | null>(draftValues?.dueDate || null);
return (
<Form
enableDrafts
actions={
<ActionPanel>
<Action.SubmitForm
onSubmit={(values: TodoValues) => {
console.log("onSubmit", values);
popToRoot();
}}
/>
</ActionPanel>
}
>
<Form.TextField id="title" title="Title" value={title} onChange={setTitle} />
<Form.TextArea id="description" title="Description" value={description} onChange={setDescription} />
<Form.DatePicker id="dueDate" title="Due Date" value={dueDate} onChange={setDueDate} />
</Form>
);
}
Prop | Description | Type | Default |
---|---|---|---|
actions | React.ReactNode | - | |
children | The Form.Item elements of the form. | React.ReactNode | - |
enableDrafts | Defines whether the Form.Items values will be preserved when user exits the screen. | boolean | false |
isLoading | Indicates whether a loading bar should be shown or hidden below the search bar | boolean | false |
navigationTitle | The main title for that view displayed in Raycast | string | Command title |
A form item with a text field for input.

Uncontrolled text field
Controlled text field
import { ActionPanel, Form, Action } from "@raycast/api";
export default function Command() {
return (
<Form
actions={
<ActionPanel>
<Action.SubmitForm title="Submit Name" onSubmit={(values) => console.log(values)} />
</ActionPanel>
}
>
<Form.TextField id="name" defaultValue="Steve" />
</Form>
);
}
import { ActionPanel, Form, Action } from "@raycast/api";
import { useState } from "react";
export default function Command() {
const [name, setName] = useState<string>("");
return (
<Form
actions={
<ActionPanel>
<Action.SubmitForm title="Submit Name" onSubmit={(values) => console.log(values)} />
</ActionPanel>
}
>
<Form.TextField id="name" value={name} onChange={setName} />
</Form>
);
}
Prop | Description | Type | Default |
---|---|---|---|
id* | ID of the form item. Make sure to assign each form item a unique id. | string | - |
autoFocus | Indicates whether the item should be focused automatically once the form is rendered. | boolean | - |
defaultValue | The default value of the item. Keep in mind that defaultValue will be configured once per component lifecycle. This means that if a user changes the value, defaultValue won't be configured on re-rendering. | string | - |
error | An optional error message to show the form item validation issues. If the error is present, the Form Item will be highlighted with red border and will show an error message on the right. | string | - |
info | An optional info message to describe the form item. It appears on the right side of the item with an info icon. When the icon is hovered, the info message is shown. | string | - |
placeholder | Placeholder text shown in the text field. | string | - |
storeValue | Indicates whether the value of the item should be persisted after submitting, and restored next time the form is rendered. | boolean | - |
title | The title displayed on the left side of the item. | string | - |
value | The current value of the item. | string | - |
onBlur | The callback that will be triggered when the item loses its focus. | (event: FormEvent<string>) => void | - |
onChange | The callback which will be triggered when the value of the item changes. | (newValue: string) => void | - |
onFocus | The callback which will be triggered should be called when the item is focused. | (event: FormEvent<string>) => void | - |
Name | Signature | Description |
---|---|---|
focus | () => void | Makes the item request focus. |
reset | () => void | Resets the form item to its initial value, or defaultValue if specified. |
A form item with a secure text field for password-entry in which the entered characters must be kept secret.

Uncontrolled password field
Controlled password field
import { ActionPanel, Form, Action } from "@raycast/api";
export default function Command() {
return (
<Form
actions={
<ActionPanel>
<Action.SubmitForm title="Submit Password" onSubmit={(values) => console.log(values)} />
</ActionPanel>
}
>
<Form.PasswordField id="password" title="Enter Password" />
</Form>
);
}
import { ActionPanel, Form, Action } from "@raycast/api";
import { useState } from "react";
export default function Command() {
const [password, setPassword] = useState<string>("");
return (
<Form
actions={
<ActionPanel>
<Action.SubmitForm title="Submit Password" onSubmit={(values) => console.log(values)} />
</ActionPanel>
}
>
<Form.PasswordField id="password" value={password} onChange={setPassword} />
</Form>
);
}
Prop | Description | Type | Default |
---|---|---|---|
id* | ID of the form item. Make sure to assign each form item a unique id. | string | - |
autoFocus | Indicates whether the item should be focused automatically once the form is rendered. | boolean | - |
defaultValue | The default value of the item. Keep in mind that defaultValue will be configured once per component lifecycle. This means that if a user changes the value, defaultValue won't be configured on re-rendering. | string | - |
error | An optional error message to show the form item validation issues. If the error is present, the Form Item will be highlighted with red border and will show an error message on the right. | string | - |
info | An optional info message to describe the form item. It appears on the right side of the item with an info icon. When the icon is hovered, the info message is shown. | string | - |
placeholder | Placeholder text shown in the password field. | string | - |
storeValue | Indicates whether the value of the item should be persisted after submitting, and restored next time the form is rendered. | boolean | - |
title | The title displayed on the left side of the item. | string | - |
value | The current value of the item. | string | - |
onBlur | The callback that will be triggered when the item loses its focus. | (event: FormEvent<string>) => void | - |
onChange | The callback which will be triggered when the value of the item changes. | (newValue: string) => void | - |
onFocus | The callback which will be triggered should be called when the item is focused. | (event: FormEvent<string>) => void | - |
Name | Signature | Description |
---|---|---|
focus | () => void | Makes the item request focus. |
reset | () => void | Resets the form item to its initial value, or defaultValue if specified. |
A form item with a text area for input. The item supports multiline text entry.

Uncontrolled text area
Controlled text area
import { ActionPanel, Form, Action } from "@raycast/api";
const DESCRIPTION =
"We spend too much time staring at loading indicators. The Raycast team is dedicated to make everybody interact faster with their computers.";
export default function Command() {
return (
<Form
actions={
<ActionPanel>
<Action.SubmitForm title="Submit Description" onSubmit={(values) => console.log(values)} />
</ActionPanel>
}
>
<Form.TextArea id="description" defaultValue={DESCRIPTION} />
</Form>
);
}
import { ActionPanel, Form, Action } from "@raycast/api";
import { useState } from "react";
export default function Command() {
const [description, setDescription] = useState<string>("");
return (
<Form
actions={
<ActionPanel>
<Action.SubmitForm title="Submit Description" onSubmit={(values) => console.log(values)} />
</ActionPanel>
}
>
<Form.TextArea id="description" value={description} onChange={setDescription} />
</Form>
);
}
Prop | Description | Type | Default |
---|---|---|---|
id* | ID of the form item. Make sure to assign each form item a unique id. | string | - |
autoFocus | Indicates whether the item should be focused automatically once the form is rendered. | boolean | - |
defaultValue | The default value of the item. Keep in mind that defaultValue will be configured once per component lifecycle. This means that if a user changes the value, defaultValue won't be configured on re-rendering. | string | - |
enableMarkdown | Whether markdown will be highlighted in the TextArea or not. When enabled, markdown shortcuts starts to work for the TextArea (pressing ⌘ + B will add **bold** around the selected text, ⌘ + I will make the selected text italic, etc.) | boolean | false |
error | An optional error message to show the form item validation issues. If the error is present, the Form Item will be highlighted with red border and will show an error message on the right. | string | - |
info | An optional info message to describe the form item. It appears on the right side of the item with an info icon. When the icon is hovered, the info message is shown. | string | - |
placeholder | Placeholder text shown in the text area. | string | - |
storeValue | Indicates whether the value of the item should be persisted after submitting, and restored next time the form is rendered. | boolean | - |
title | The title displayed on the left side of the item. | string | - |
value | The current value of the item. | string | - |
onBlur | The callback that will be triggered when the item loses its focus. | (event: FormEvent<string>) => void | - |
onChange | The callback which will be triggered when the value of the item changes. | (newValue: string) => void | - |
onFocus | The callback which will be triggered should be called when the item is focused. | (event: FormEvent<string>) => void | - |
Name | Signature | Description |
---|---|---|
focus | () => void | Makes the item request focus. |
reset | () => void | Resets the form item to its initial value, or defaultValue if specified. |
A form item with a checkbox.

Uncontrolled checkbox
Controlled checkbox
import { ActionPanel, Form, Action } from "@raycast/api";
export default function Command() {
return (
<Form
actions={
<ActionPanel>
<Action.SubmitForm title="Submit Answer" onSubmit={(values) => console.log(values)} />
</ActionPanel>
}
>
<Form.Checkbox id="answer" label="Are you happy?" defaultValue={true} />
</Form>
);
}
import { ActionPanel, Form, Action } from "@raycast/api";
import { useState } from "react";
export default function Command() {
const [checked, setChecked] = useState(true);
return (
<Form
actions={
<ActionPanel>
<Action.SubmitForm title="Submit Answer" onSubmit={(values) => console.log(values)} />
</ActionPanel>
}
>
<Form.Checkbox id="answer" label="Do you like orange juice?" value={checked} onChange={setChecked} />
</Form>
);
}
Prop | Description | Type | Default |
---|---|---|---|
id* | ID of the form item. Make sure to assign each form item a unique id. | string | - |
label* | The label displayed on the right side of the checkbox. | string | - |
autoFocus | Indicates whether the item should be focused automatically once the form is rendered. | boolean | - |
defaultValue | The default value of the item. Keep in mind that defaultValue will be configured once per component lifecycle. This means that if a user changes the value, defaultValue won't be configured on re-rendering. | boolean | - |
error | An optional error message to show the form item validation issues. If the error is present, the Form Item will be highlighted with red border and will show an error message on the right. | string | - |
info | An optional info message to describe the form item. It appears on the right side of the item with an info icon. When the icon is hovered, the info message is shown. | string | - |
storeValue | Indicates whether the value of the item should be persisted after submitting, and restored next time the form is rendered. | boolean | - |
title | The title displayed on the left side of the item. | string | - |
value | The current value of the item. | boolean | - |
onBlur | The callback that will be triggered when the item loses its focus. | (event: FormEvent<boolean>) => void | - |
onChange | The callback which will be triggered when the value of the item changes. | (newValue: boolean) => void | - |
onFocus | The callback which will be triggered should be called when the item is focused. | (event: FormEvent<boolean>) => void | - |
Name | Signature | Description |
---|---|---|
focus | () => void | Makes the item request focus. |
reset | () => void | Resets the form item to its initial value, or defaultValue if specified. |
A form item with a date picker.

Uncontrolled date picker
Controlled date picker
import { ActionPanel, Form, Action } from "@raycast/api";
export default function Command() {
return (
<Form
actions={
<ActionPanel>
<Action.SubmitForm title="Submit Form" onSubmit={(values) => console.log(values)} />
</ActionPanel>
}
>
<Form.DatePicker id="dateOfBirth" title="Date of Birth" defaultValue={new Date(1955, 1, 24)} />
</Form>
);
}
import { ActionPanel, Form, Action } from "@raycast/api";
import { useState } from "react";
export default function Command() {
const [date, setDate] = useState<Date | null>(null);
return (
<Form
actions={
<ActionPanel>
<Action.SubmitForm title="Submit Form" onSubmit={(values) => console.log(values)} />
</ActionPanel>
}
>
<Form.DatePicker id="launchDate" title="Launch Date" value={date} onChange={setDate} />
</Form>
);
}
Prop | Description | Type | Default |
---|---|---|---|
id* | ID of the form item. Make sure to assign each form item a unique id. |
|