Comment on page
List
The de-facto user interface in Raycast. Ideal to present similar data such as to-dos or files.
Our
List
component provides great user experience out of the box:- Use built-in filtering for best performance.
- Group-related items in sections with titles and subtitles.
- Show loading indicator for longer operations.
- Use the search query for typeahead experiences, optionally throttled.

The search bar allows users to interact quickly with list items. By default, List.Items are displayed if the user's input can be (fuzzy) matched to the item's
title
or keywords
.Sometimes, you may not want to rely on Raycast's filtering, but use/implement your own. If that's the case, you can set the
List
's filtering
prop to false, and the items displayed will be independent of the search bar's text. Note that filtering
is also implicitly set to false if an onSearchTextChange
listener is specified. If you want to specify a change listener and still take advantage of Raycast's built-in filtering, you can explicitly set filtering
to true.import { useEffect, useState } from "react";
import { Action, ActionPanel, List } from "@raycast/api";
const items = ["Augustiner Helles", "Camden Hells", "Leffe Blonde", "Sierra Nevada IPA"];
export default function Command() {
const [searchText, setSearchText] = useState("");
const [filteredList, filterList] = useState(items);
useEffect(() => {
filterList(items.filter((item) => item.includes(searchText)));
}, [searchText]);
return (
<List
filtering={false}
onSearchTextChange={setSearchText}
navigationTitle="Search Beers"
searchBarPlaceholder="Search your favorite beer"
>
{filteredList.map((item) => (
<List.Item
key={item}
title={item}
actions={
<ActionPanel>
<Action title="Select" onAction={() => console.log(`${item} selected`)} />
</ActionPanel>
}
/>
))}
</List>
);
}
Other times, you may want the content of the search bar to be updated by the extension, for example, you may store a list of the user's previous searches and, on the next visit, allow them to "continue" where they left off.
import { useEffect, useState } from "react";
import { Action, ActionPanel, List } from "@raycast/api";
const items = ["Augustiner Helles", "Camden Hells", "Leffe Blonde", "Sierra Nevada IPA"];
export default function Command() {
const [searchText, setSearchText] = useState("");
return (
<List
searchText={searchText}
onSearchTextChange={setSearchText}
navigationTitle="Search Beers"
searchBarPlaceholder="Search your favorite beer"
>
{items.map((item) => (
<List.Item
key={item}
title={item}
actions={
<ActionPanel>
<Action title="Select" onAction={() => setSearchText(item)} />
</ActionPanel>
}
/>
))}
</List>
);
}
Some extensions may benefit from giving users a second filtering dimension. A todo extension may allow users to use different groups, a newspaper-reading extension may want to allow quickly switching categories, etc.
This is where the
searchBarAccessory
prop is useful. Pass it a List.Dropdown component, and it will be displayed on the right-side of the search bar. Invoke it either by using the global shortcut ⌘
P
or by clicking on it.List.tsx
ListWithSections.tsx
ListWithActions.tsx
ListWithDetail.tsx
ListWithEmptyView.tsx
import { List } from "@raycast/api";
export default function Command() {
return (
<List>
<List.Item title="Item 1" />
<List.Item title="Item 2" subtitle="Optional subtitle" />
</List>
);
}
import { List } from "@raycast/api";
export default function Command() {
return (
<List>
<List.Section title="Section 1">
<List.Item title="Item 1" />
</List.Section>
<List.Section title="Section 2" subtitle="Optional subtitle">
<List.Item title="Item 1" />
</List.Section>
</List>
);
}
import { ActionPanel, Action, List } from "@raycast/api";
export default function Command() {
return (
<List>
<List.Item
title="Item 1"
actions={
<ActionPanel>
<Action.CopyToClipboard content="👋" />
</ActionPanel>
}
/>
</List>
);
}
import { useState } from "react";
import { Action, ActionPanel, List } from "@raycast/api";
import { useCachedPromise } from "@raycast/utils";
interface Pokemon {
name: string;
height: number;
weight: number;
id: string;
types: string[];
abilities: Array<{ name: string; isMainSeries: boolean }>;
}
const pokemons: Pokemon[] = [
{
name: "bulbasaur",
height: 7,
weight: 69,
id: "001",
types: ["Grass", "Poison"],
abilities: [
{ name: "Chlorophyll", isMainSeries: true },
{ name: "Overgrow", isMainSeries: true },
],
},
{
name: "ivysaur",
height: 10,
weight: 130,
id: "002",
types: ["Grass", "Poison"],
abilities: [
{ name: "Chlorophyll", isMainSeries: true },
{ name: "Overgrow", isMainSeries: true },
],
},
];
export default function Command() {
const [showingDetail, setShowingDetail] = useState(true);
const { data, isLoading } = useCachedPromise(() => new Promise<Pokemon[]>((resolve) => resolve(pokemons)));
return (
<List isLoading={isLoading} isShowingDetail={showingDetail}>
{data &&
data.map((pokemon) => {
const props: Partial<List.Item.Props> = showingDetail
? {
detail: (
<List.Item.Detail
markdown={`\n\n${pokemon.types.join(" ")}`}
/>
),
}
: { accessories: [{ text: pokemon.types.join(" ") }] };
return (
<List.Item
key={pokemon.id}
title={pokemon.name}
subtitle={`#${pokemon.id}`}
{...props}
actions={
<ActionPanel>
<Action.OpenInBrowser url={`https://www.pokemon.com/us/pokedex/${pokemon.name}`} />
<Action title="Toggle Detail" onAction={() => setShowingDetail(!showingDetail)} />
</ActionPanel>
}
/>
);
})}
</List>
);
}
import { useEffect, useState } from "react";
import { List } from "@raycast/api";
export default function CommandWithCustomEmptyView() {
const [state, setState] = useState({ searchText: "", items: [] });
useEffect(() => {
// perform an API call that eventually populates `items`.
}, [state.searchText]);
return (
<List onSearchTextChange={(newValue) => setState((previous) => ({ ...previous, searchText: newValue }))}>
{state.searchText === "" && state.items.length === 0 ? (
<List.EmptyView icon={{ source: "https://placekitten.com/500/500" }} title="Type something to get started" />
) : (
state.items.map((item) => <List.Item key={item} title={item} />)
)}
</List>
);
}
The list uses built-in filtering by indexing the title of list items and additionally keywords.
import { List } from "@raycast/api";
export default function Command() {
return (
<List navigationTitle="Search Beers" searchBarPlaceholder="Search your favorite beer">
<List.Item title="Augustiner Helles" />
<List.Item title="Camden Hells" />
<List.Item title="Leffe Blonde" />
<List.Item title="Sierra Nevada IPA" />
</List>
);
}
Prop | Description | Type | Default |
---|---|---|---|
actions | React.ReactNode | - | |
children | List sections or items. If List.Item elements are specified, a default section is automatically created. | React.ReactNode | - |
filtering | Toggles Raycast filtering. When true , Raycast will use the query in the search bar to filter the items. When false , the extension needs to take care of the filtering. | boolean or { keepSectionOrder: boolean } | false when onSearchTextChange is specified, true otherwise. |
isLoading | Indicates whether a loading bar should be shown or hidden below the search bar | boolean | false |
isShowingDetail | Whether the List should have an area on the right side of the items to show additional details about the selected item. | boolean | - |
navigationTitle | The main title for that view displayed in Raycast | string | Command title |
searchBarAccessory | - | ||
searchBarPlaceholder | Placeholder text that will be shown in the search bar. | string | "Search…" |
searchText | The text that will be displayed in the search bar. | string | - |
selectedItemId | Selects the item with the specified id. | string | - |
throttle | Defines whether the onSearchTextChange handler will be triggered on every keyboard press or with a delay for throttling the events. Recommended to set to true when using custom filtering logic with asynchronous operations (e.g. network requests). | boolean | false |
onSearchTextChange | Callback triggered when the search bar text changes. | (text: string) => void | - |
onSelectionChange | Callback triggered when the item selection in the list changes. | (id: string) => void | - |
A dropdown menu that will be shown in the right-hand-side of the search bar.
import { List } from "@raycast/api";
type DrinkType = { id: string; name: string };
function DrinkDropdown(props: { drinkTypes: DrinkType[]; onDrinkTypeChange: (newValue: string) => void }) {
const { drinkTypes, onDrinkTypeChange } = props;
return (
<List.Dropdown
tooltip="Select Drink Type"
storeValue={true}
onChange={(newValue) => {
onDrinkTypeChange(newValue);
}}
>
<List.Dropdown.Section title="Alcoholic Beverages">
{drinkTypes.map((drinkType) => (
<List.Dropdown.Item key={drinkType.id} title={drinkType.name} value={drinkType.id} />
))}
</List.Dropdown.Section>
</List.Dropdown>
);
}
export default function Command() {
const drinkTypes: DrinkType[] = [
{ id: "1", name: "Beer" },
{ id: "2", name: "Wine" },
];
const onDrinkTypeChange = (newValue: string) => {
console.log(newValue);
};
return (
<List
navigationTitle="Search Beers"
searchBarPlaceholder="Search your favorite drink"
searchBarAccessory={<DrinkDropdown drinkTypes={drinkTypes} onDrinkTypeChange={onDrinkTypeChange} />}
>
<List.Item title="Augustiner Helles" />
<List.Item title="Camden Hells" />
<List.Item title="Leffe Blonde" />
<List.Item title="Sierra Nevada IPA" />
</List>
);
}
Prop | Description | Type | Default |
---|---|---|---|
tooltip* | Tooltip displayed when hovering the dropdown. | string | - |
children | Dropdown sections or items. If Dropdown.Item elements are specified, a default section is automatically created. | React.ReactNode | - |
defaultValue | The default value of the dropdown. 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 | - |
filtering | Toggles Raycast filtering. When true , Raycast will use the query in the search bar to filter the items. When false , the extension needs to take care of the filtering. | boolean or { keepSectionOrder: boolean } | false when onSearchTextChange is specified, true otherwise. |
id | ID of the dropdown. | string | - |
isLoading | Indicates whether a loading indicator should be shown or hidden next to the search bar | boolean | false |
placeholder | Placeholder text that will be shown in the dropdown search field. | string | "Search…" |
storeValue | Indicates whether the value of the dropdown should be persisted after selection, and restored next time the dropdown is rendered. | boolean | - |
throttle | Defines whether the onSearchTextChange handler will be triggered on every keyboard press or with a delay for throttling the events. Recommended to set to true when using custom filtering logic with asynchronous operations (e.g. network requests). | boolean | false |
value | The currently value of the dropdown. | string | - |
onChange | Callback triggered when the dropdown selection changes. | (newValue: string) => void | - |
onSearchTextChange | Callback triggered when the search bar text changes. | (text: string) => void | - |
import { List } from "@raycast/api";
export default function Command() {
return (
<List
searchBarAccessory={
<List.Dropdown tooltip="Dropdown With Items">
<List.Dropdown.Item title="One" value="one" />
<List.Dropdown.Item title="Two" value="two" />
<List.Dropdown.Item title="Three" value="three" />
</List.Dropdown>
}
>
<List.Item title="Item in the Main List" />
</List>
);
}
Prop | Description | Type | Default |
---|---|---|---|
title* | The title displayed for the item. | string | - |
value* | Value of the dropdown item. Make sure to assign each unique value for each item. | string | - |
icon | An optional icon displayed for the item. | - | |
keywords | An optional property used for providing additional indexable strings for search. When filtering the items in Raycast, the keywords will be searched in addition to the title. | string[] | The title of its section if any |
Visually separated group of dropdown items.
Use sections to group related menu items together.
import { List } from "@raycast/api";
export default function Command() {
return (
<List
searchBarAccessory={
<List.Dropdown tooltip="Dropdown With Sections">
<List.Dropdown.Section title="First Section">
<List.Dropdown.Item title="One" value="one" />
</List.Dropdown.Section>
<List.Dropdown.Section title="Second Section">
<List.Dropdown.Item title="Two" value="two" />
</List.Dropdown.Section>
</List.Dropdown>
}
>
<List.Item title="Item in the Main List" />
</List>
);
}
Prop | Description | Type | Default |
---|---|---|---|
children | The item elements of the section. | React.ReactNode | - |
title | Title displayed above the section | string | - |
A view to display when there aren't any items available. Use to greet users with a friendly message if the extension requires user input before it can show any list items e.g. when searching for a package, an article etc.
Raycast provides a default
EmptyView
that will be displayed if the List component either has no children, or if it has children, but none of them match the query in the search bar. This too can be overridden by passing an empty view alongside the other List.Item
s.Note that the
EmptyView
is never displayed if the List
's isLoading
property is true and the search bar is empty.
List EmptyView illustration
import { useEffect, useState } from "react";
import { List } from "@raycast/api";
export default function CommandWithCustomEmptyView() {
const [state, setState] = useState({ searchText: "", items: [] });
useEffect(() => {
// perform an API call that eventually populates `items`.
}, [state.searchText]);
return (
<List onSearchTextChange={(newValue) => setState((previous) => ({ ...previous, searchText: newValue }))}>
{state.searchText === "" && state.items.length === 0 ? (
<List.EmptyView icon={{ source: "https://placekitten.com/500/500" }} title="Type something to get started" />
) : (
state.items.map((item) => <List.Item key={item} title={item} />)
)}
</List>
);
}
Prop | Description | Type | Default |
---|---|---|---|
actions | React.ReactNode | - | |
description | An optional description for why the empty view is shown. | string | - |
icon | An icon displayed in the center of the EmptyView. | - | |
title | The main title displayed for the Empty View. | string | - |
This is one of the foundational UI components of Raycast. A list item represents a single entity. It can be a GitHub pull request, a file, or anything else. You most likely want to perform actions on this item, so make it clear to the user what this list item is about.
import { Icon, List } from "@raycast/api";
export default function Command() {
return (
<List>
<List.Item icon={Icon.Star} title="Augustiner Helles" subtitle="0,5 Liter" accessories={[{ text: "Germany" }]} />
</List>
);
}
Prop | Description | Type | Default |
---|---|---|---|
title* | The main title displayed for that item, optionally with a tooltip. | string or { tooltip?: string; value: string } | - |
accessories | - | ||
actions | React.ReactNode | - | |
detail | The List.Item.Detail to be rendered in the right side area when the parent List is showing details and the item is selected. | React.ReactNode | - |
icon | An optional icon displayed for the list item. | - | |
id | ID of the item. This string is passed to the onSelectionChange handler of the List when the item is selected. Make sure to assign each item a unique ID or a UUID will be auto generated. | string | - |
keywords | An optional property used for providing additional indexable strings for search. When filtering the list in Raycast through the search bar, the keywords will be searched in addition to the title. | string[] | - |
quickLook | Optional information to preview files with Quick Look. Toggle the preview with Action.ToggleQuickLook. | { name?: string; path: string } | - |
subtitle | An optional subtitle displayed next to the main title, optionally with a tooltip. | string or { tooltip?: string; value?: string } | - |
A Detail view that will be shown in the right-hand-side of the
List
.When shown, it is recommended not to show any accessories on the
List.Item
and instead bring those additional information in the List.Item.Detail
view.
List-detail illustration
import { List } from "@raycast/api";
export default function Command() {
return (
<List isShowingDetail>
<List.Item
title="Pikachu"
subtitle="Electric"
detail={
<List.Item.Detail markdown="" />
}
/>
</List>
);
}
Prop | Description | Type | Default |
---|---|---|---|
isLoading | Indicates whether a loading bar should be shown or hidden above the detail | boolean | false |
markdown | The CommonMark string to be rendered in the right side area when the parent List is showing details and the item is selected. | string | - |
metadata | The List.Item.Detail.Metadata to be rendered in the bottom side of the List.Item.Detail | React.ReactNode | - |
A Metadata view that will be shown in the bottom side of the
List.Item.Detail
.Use it to display additional structured data about the content of the
List.Item
.Metadata + Markdown
Metadata Standalone

List Detail-metadata illustration