# AI The AI API provides developers with seamless access to AI functionality without requiring API keys, configuration, or extra dependencies. {% hint style="info" %} Some users might not have access to this API. If a user doesn't have access to Raycast Pro, they will be asked if they want to get access when your extension calls the AI API. If the user doesn't wish to get access, the API call will throw an error. You can check if a user has access to the API using `environment.canAccess(AI)`. {% endhint %} ## API Reference ### AI.ask Ask AI anything you want. Use this in “no-view” Commands, effects, or callbacks. In a React component, you might want to use the useAI util hook instead. #### Signature ```typescript async function ask(prompt: string, options?: AskOptions): Promise & EventEmitter; ``` #### Example {% tabs %} {% tab title="Basic Usage" %} ```typescript import { AI, Clipboard } from "@raycast/api"; export default async function command() { const answer = await AI.ask("Suggest 5 jazz songs"); await Clipboard.copy(answer); } ``` {% endtab %} {% tab title="Error handling" %} ```typescript import { AI, showToast, Toast } from "@raycast/api"; export default async function command() { try { await AI.ask("Suggest 5 jazz songs"); } catch (error) { // Handle error here, eg: by showing a Toast await showToast({ style: Toast.Style.Failure, title: "Failed to generate answer", }); } } ``` {% endtab %} {% tab title="Stream answer" %} ```typescript import { AI, getSelectedFinderItems, showHUD } from "@raycast/api"; import fs from "fs"; export default async function main() { let allData = ""; const [file] = await getSelectedFinderItems(); const answer = AI.ask("Suggest 5 jazz songs"); // Listen to "data" event to stream the answer answer.on("data", async (data) => { allData += data; await fs.promises.writeFile(`${file.path}`, allData.trim(), "utf-8"); }); await answer; await showHUD("Done!"); } ``` {% endtab %} {% tab title="User Feedback" %} ```typescript import { AI, getSelectedFinderItems, showHUD } from "@raycast/api"; import fs from "fs"; export default async function main() { let allData = ""; const [file] = await getSelectedFinderItems(); // If you're doing something that happens in the background // Consider showing a HUD or a Toast as the first step // To give users feedback about what's happening await showHUD("Generating answer..."); const answer = await AI.ask("Suggest 5 jazz songs"); await fs.promises.writeFile(`${file.path}`, allData.trim(), "utf-8"); // Then, when everythig is done, notify the user again await showHUD("Done!"); } ``` {% endtab %} {% tab title="Check for access" %} ```typescript import { AI, getSelectedFinderItems, showHUD, environment } from "@raycast/api"; import fs from "fs"; export default async function main() { if (environment.canAccess(AI)) { const answer = await AI.ask("Suggest 5 jazz songs"); await Clipboard.copy(answer); } else { await showHUD("You don't have access :("); } } ``` {% endtab %} {% endtabs %} #### Parameters | Name | Description | Type | | :--- | :--- | :--- | | prompt* | The prompt to ask the AI. | string | | options | Options to control which and how the AI model should behave. | AI.AskOptions | #### Return A Promise that resolves with a prompt completion. ## Types ### AI.Creativity Concrete tasks, such as fixing grammar, require less creativity while open-ended questions, such as generating ideas, require more. ```typescript type Creativity = "none" | "low" | "medium" | "high" | "maximum" | number; ``` If a number is passed, it needs to be in the range 0-2. For larger values, 2 will be used. For lower values, 0 will be used. ### AI.Model The AI model to use to answer to the prompt. Defaults to `AI.Model["OpenAI_GPT3.5-turbo"]`. #### Enumeration members | Model | Description | | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | OpenAI_GPT4 | GPT-4 is the model with broad general knowledge, allowing it to follow complex instructions and solve difficult problems. This model is the previous generation, use GPT-4o for better results. | | OpenAI_GPT4-turbo | GPT-4 Turbo is an evolution of the GPT-4 model with a larger context. This model is the previous generation, use gpt-4o for better results. | | OpenAI_GPT4o | GPT-4o is the most advanced and fastest model from OpenAI, making it a great choice for complex everyday problems and deeper conversations. | | OpenAI_GPT4o-mini | GPT-4o mini is a highly intelligent and fast model that is ideal for a variety of everyday tasks. | | Anthropic_Claude_Haiku | Claude 3.5 Haiku is Anthropic's fastest model, with a large context window that makes it ideal for analyzing code, documents, or large amounts of text. | | Anthropic_Claude_Sonnet | Claude 3.5 Sonnet from Anthropic has enhanced intelligence with increased speed. It excels at complex tasks like visual reasoning or workflow orchestrations. | | Anthropic_Claude_Opus | Claude 3 Opus is Anthropic's intelligent model designed to solve highly complex tasks. It stands out for its remarkable fluency. | | Perplexity_Llama3.1_Sonar_Small | Perplexity's Llama 3.1 Sonar Small is built for speed. It quickly gives you helpful answers using the latest internet knowledge while minimizing hallucinations. | | Perplexity_Llama3.1_Sonar_Large | Perplexity's advanced model. Can handle complex questions. It considers current web knowledge to provide well-reasoned, in-depth answers. | | Perplexity_Llama3.1_Sonar_Huge | Perplexity's most advanced model. Offers performance that is on par with state of the art models today. | | Llama3.3_70B | Llama 3.3 70B is an open-source model from Meta, state-of-the-art in areas like reasoning, math, and general knowledge. | | Llama3.1_8B | Llama 3.1 8B is an open-source model from Meta, optimized for instruction following and high-speed performance. Powered by Groq. | | Llama3_70B | Llama 3 70B from Meta is a highly capable open-source LLM that can serve as a tool for various text-related tasks. Powered by Groq. | | Llama3.1_405B | Llama 3.1 405B is Meta's flagship open-source model, offering unparalleled capabilities in general knowledge, steerability, math, tool use, and multilingual translation. Powered by together.ai | | MixtraL_8x7B | Mixtral 8x7B from Mistral is an open-source model that demonstrates high performance in generating code and text at an impressive speed. Powered by Groq. | | Mistral_Nemo | Mistral Nemo is a small model built in collaboration with NVIDIA, and released under the Apache 2.0 license. | | Mistral_Large2 | Mistral Large is Mistral's flagship model, capable of code generation, mathematics, and reasoning, with stronger multilingual support. | If a model isn't available to the user, Raycast will fallback to a similar one: - `AI.Model.Anthropic_Claude_Opus` and `AI.Model.Anthropic_Claude_Sonnet` -> `AI.Model.Anthropic_Claude_Haiku` - `AI.Model.OpenAI_GPT4` and `AI.Model["OpenAI_GPT4-turbo"]` -> `AI.Model["OpenAI_GPT4o-mini"]` - `AI.Model["Perplexity_Llama3.1_Sonar_Large"]` and `AI.Model["Perplexity_Llama3.1_Sonar_Huge"]` -> `AI.Model["Perplexity_Llama3.1_Sonar_Small"]` - `AI.Model.Mistral_Large2` -> `AI.Model.Mistral_Nemo` - `AI.Model["Llama3.1_405B"]` -> `AI.Model["Llama3.3_70B"]` ### AI.AskOptions #### Properties | Property | Description | Type | | :--- | :--- | :--- | | creativity | Concrete tasks, such as fixing grammar, require less creativity while open-ended questions, such as generating ideas, require more. If a number is passed, it needs to be in the range 0-2. For larger values, 2 will be used. For lower values, 0 will be used. | AI.Creativity | | model | The AI model to use to answer to the prompt. | AI.Model | | signal | Abort signal to cancel the request. | AbortSignal | # Browser Extension The Browser Extension API provides developers with deeper integration into the user's Browser _via_ a [Browser Extension](https://raycast.com/browser-extension). {% hint style="info" %} Some users might not have installed the Browser Extension. If a user doesn't have the Browser Extension installed, they will be asked if they want to install it when your extension calls the Browser Extension API. If the user doesn't wish to install it, the API call will throw an error. You can check if a user has the Browser Extension installed using `environment.canAccess(BrowserExtension)`. {% endhint %} ## API Reference ### BrowserExtension.getContent Get the content of an opened browser tab. #### Signature ```typescript async function getContent(options?: { cssSelector?: string; tabId?: number; format?: "html" | "text" | "markdown"; }): Promise; ``` #### Example {% tabs %} {% tab title="Basic Usage" %} ```typescript import { BrowserExtension, Clipboard } from "@raycast/api"; export default async function command() { const markdown = await BrowserExtension.getContent({ format: "markdown" }); await Clipboard.copy(markdown); } ``` {% endtab %} {% tab title="CSS Selector" %} ```typescript import { BrowserExtension, Clipboard } from "@raycast/api"; export default async function command() { const title = await BrowserExtension.getContent({ format: "text", cssSelector: "title" }); await Clipboard.copy(title); } ``` {% endtab %} {% endtabs %} #### Parameters | Name | Description | Type | | :--- | :--- | :--- | | options | Options to control which content to get. | Object | | options.cssSelector | Only returns the content of the element that matches the [CSS selector](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_selectors). | string | | options.format | The format of the content. | "html" or "text" or "markdown" | | options.tabId | The ID of the tab to get the content from. If not specified, the content of the active tab of the focused window is returned. | number | #### Return A Promise that resolves with the content of the tab. ### BrowserExtension.getTabs Get the list of open browser tabs. #### Signature ```typescript async function getTabs(): Promise; ``` #### Example ```typescript import { BrowserExtension } from "@raycast/api"; export default async function command() { const tabs = await BrowserExtension.getTabs(); console.log(tabs); } ``` #### Return A Promise that resolves with the list of tabs. ## Types ### BrowserExtension.Tab #### Properties | Property | Description | Type | | :--- | :--- | :--- | | active* | Whether the tab is active in its window. There can only be one active tab per window but if there are multiple browser windows, there can be multiple active tabs. | boolean | | id* | The ID of the tab. Tab IDs are unique within a browser session. | number | | url* | The URL the tab is displaying. | string | | favicon | The URL of the tab's [favicon](https://developer.mozilla.org/en-US/docs/Glossary/Favicon). It may also be `undefined` if the tab is loading. | string | | title | The title of the tab. It may also be `undefined` if the tab is loading. | string | # Caching Caching abstraction that stores data on disk and supports LRU (least recently used) access. Since extensions can only consume up to a max. heap memory size, the cache only maintains a lightweight index in memory and stores the actual data in separate files on disk in the extension's support directory. ## API Reference ### Cache The `Cache` class provides CRUD-style methods (get, set, remove) to update and retrieve data synchronously based on a key. The data must be a string and it is up to the client to decide which serialization format to use. A typical use case would be to use `JSON.stringify` and `JSON.parse`. By default, the cache is shared between the commands of an extension. Use Cache.Options. #### Signature ```typescript constructor(options: Cache.Options): Cache ``` #### Example ```typescript import { List, Cache } from "@raycast/api"; type Item = { id: string; title: string }; const cache = new Cache(); cache.set("items", JSON.stringify([{ id: "1", title: "Item 1" }])); export default function Command() { const cached = cache.get("items"); const items: Item[] = cached ? JSON.parse(cached) : []; return ( {items.map((item) => ( ))} ); } ``` #### Properties | Property | Description | Type | | :---------------------------------------- | :------------------------------------------------------- | :------------------- | | isEmpty\* | Returns `true` if the cache is empty, `false` otherwise. | boolean | #### Methods | Method | | :------------------------------------------------------------------------------------------- | | get(key: string): string \| undefined | | has(key: string): boolean | | set(key: string, data: string): void | | remove(key: string): boolean | | clear(options = { notifySubscribers: true }): void | | subscribe(subscriber: Cache.Subscriber): Cache.Subscription | ### Cache#get Returns the data for the given key. If there is no data for the key, `undefined` is returned. If you want to just check for the existence of a key, use has. #### Signature ```typescript get(key: string): string | undefined ``` #### Parameters | Name | Description | Type | | :------------------------------------ | :-------------------------- | :------------------ | | key\* | The key of the Cache entry. | string | ### Cache#has Returns `true` if data for the key exists, `false` otherwise. You can use this method to check for entries without affecting the LRU access. #### Signature ```typescript has(key: string): boolean ``` #### Parameters | Name | Description | Type | | :------------------------------------ | :-------------------------- | :------------------ | | key\* | The key of the Cache entry. | string | ### Cache#set Sets the data for the given key. If the data exceeds the configured `capacity`, the least recently used entries are removed. This also notifies registered subscribers (see subscribe. #### Signature ```typescript set(key: string, data: string) ``` #### Parameters | Name | Description | Type | | :------------------------------------- | :--------------------------------------- | :------------------ | | key\* | The key of the Cache entry. | string | | data\* | The stringified data of the Cache entry. | string | ### Cache#remove Removes the data for the given key. This also notifies registered subscribers (see subscribe. Returns `true` if data for the key was removed, `false` otherwise. #### Signature ```typescript remove(key: string): boolean ``` ### Cache#clear Clears all stored data. This also notifies registered subscribers (see subscribe unless the `notifySubscribers` option is set to `false`. #### Signature ```typescript clear((options = { notifySubscribers: true })); ``` #### Parameters | Name | Description | Type | | :------ | :------------------------------------------------------------------------------------------------------------------------- | :------------------ | | options | Options with a `notifySubscribers` property. The default is `true`; set to `false` to disable notification of subscribers. | object | ### Cache#subscribe Registers a new subscriber that gets notified when cache data is set or removed. Returns a function that can be called to remove the subscriber. #### Signature ```typescript subscribe(subscriber: Cache.Subscriber): Cache.Subscription ``` #### Parameters | Name | Description | Type | | :--------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------- | | subscriber | A function that is called when the Cache is updated. The function receives two values: the `key` of the Cache entry that was updated or `undefined` when the Cache is cleared, and the associated `data`. | Cache.Subscriber | ## Types ### Cache.Options The options for creating a new Cache. #### Properties | Property | Description | Type | | :--- | :--- | :--- | | capacity | The capacity in bytes. If the stored data exceeds the capacity, the least recently used data is removed. The default capacity is 10 MB. | number | | namespace | If set, the Cache will be namespaced via a subdirectory. This can be useful to separate the caches for individual commands of an extension. By default, the cache is shared between the commands of an extension. | string | ### Cache.Subscriber Function type used as parameter for subscribe. ```typescript type Subscriber = (key: string | undefined, data: string | undefined) => void; ``` ### Cache.Subscription Function type returned from subscribe. ```typescript type Subscription = () => void; ``` # Clipboard Use the Clipboard APIs to work with content from your clipboard. You can write contents to the clipboard through `Clipboard.copy` function inserts text at the current cursor position in your frontmost app. The action `Action.CopyToClipboard` can be used to insert text in your frontmost app. ## API Reference ### Clipboard.copy Copies text or a file to the clipboard. #### Signature ```typescript async function copy(content: string | number | Content, options?: CopyOptions): Promise; ``` #### Example ```typescript import { Clipboard } from "@raycast/api"; export default async function Command() { // copy some text await Clipboard.copy("https://raycast.com"); const textContent: Clipboard.Content = { text: "https://raycast.com", }; await Clipboard.copy(textContent); // copy a file const file = "/path/to/file.pdf"; try { const fileContent: Clipboard.Content = { file }; await Clipboard.copy(fileContent); } catch (error) { console.log(`Could not copy file '${file}'. Reason: ${error}`); } // copy confidential data await Clipboard.copy("my-secret-password", { concealed: true }); } ``` #### Parameters | Name | Description | Type | | :--- | :--- | :--- | | content* | The content to copy to the clipboard. | string or number or Clipboard.Content | | options | Options for the copy operation. | Clipboard.CopyOptions | #### Return A Promise that resolves when the content is copied to the clipboard. ### Clipboard.paste Pastes text or a file to the current selection of the frontmost application. #### Signature ```typescript async function paste(content: string | Content): Promise; ``` #### Example ```typescript import { Clipboard } from "@raycast/api"; export default async function Command() { await Clipboard.paste("I really like Raycast's API"); } ``` #### Parameters | Name | Description | Type | | :--- | :--- | :--- | | content* | The content to insert at the cursor. | string or number or Clipboard.Content | #### Return A Promise that resolves when the content is pasted. ### Clipboard.clear Clears the current clipboard contents. #### Signature ```typescript async function clear(): Promise; ``` #### Example ```typescript import { Clipboard } from "@raycast/api"; export default async function Command() { await Clipboard.clear(); } ``` #### Return A Promise that resolves when the clipboard is cleared. ### Clipboard.read Reads the clipboard content as plain text, file name, or HTML. #### Signature ```typescript async function read(options?: { offset?: number }): Promise; ``` #### Example ```typescript import { Clipboard } from "@raycast/api"; export default async () => { const { text, file, html } = await Clipboard.read(); console.log(text); console.log(file); console.log(html); }; ``` #### Parameters | Name | Description | Type | | :--- | :--- | :--- | | options | Options for the read operation. | Object | | options.offset | Specify an offset to access the Clipboard History. Minimum value is 0, maximum value is 5. | number | #### Return A promise that resolves when the clipboard content was read as plain text, file name, or HTML. ### Clipboard.readText Reads the clipboard as plain text. #### Signature ```typescript async function readText(options?: { offset?: number }): Promise; ``` #### Example ```typescript import { Clipboard } from "@raycast/api"; export default async function Command() { const text = await Clipboard.readText(); console.log(text); } ``` #### Parameters | Name | Description | Type | | :--- | :--- | :--- | | options | Options for the readText operation. | Object | | options.offset | Specify an offset to access the Clipboard History. Minimum value is 0, maximum value is 5. | number | #### Return A promise that resolves once the clipboard content is read as plain text. ## Types ### Clipboard.Content Type of content that is copied and pasted to and from the Clipboard ```typescript type Content = | { text: string; } | { file: PathLike; } | { html: string; text?: string; // The alternative text representation of the content. }; ``` ### Clipboard.ReadContent Type of content that is read from the Clipboard ```typescript type Content = | { text: string; } | { file?: string; } | { html?: string; }; ``` ### Clipboard.CopyOptions Type of options passed to `Clipboard.copy`. #### Properties | Property | Description | Type | | :--- | :--- | :--- | | concealed | Indicates whether the content be treated as confidential. If `true`, it will not be recorded in the Clipboard History. | boolean | # Command-related Utilities This set of utilities to work with Raycast commands. ## API Reference ### launchCommand Launches another command. If the command does not exist, or if it's not enabled, an error will be thrown. If the command is part of another extension, the user will be presented with a permission alert. Use this method if your command needs to open another command based on user interaction, or when an immediate background refresh should be triggered, for example when a command needs to update an associated menu-bar command. #### Signature ```typescript export async function launchCommand(options: LaunchOptions): Promise; ``` #### Example ```typescript import { launchCommand, LaunchType } from "@raycast/api"; export default async function Command() { await launchCommand({ name: "list", type: LaunchType.UserInitiated, context: { foo: "bar" } }); } ``` #### Parameters | Name | Description | Type | | :--- | :--- | :--- | | options* | Options to launch a command within the same extension or in another extension. | LaunchOptions | #### Return A Promise that resolves when the command has been launched. (Note that this does not indicate that the launched command has finished executing.) ### updateCommandMetadata Update the values of properties declared in the manifest of the current command. Note that currently only `subtitle` is supported. Pass `null` to clear the custom subtitle. {% hint style="info" %} The actual manifest file is not modified, so the update applies as long as the command remains installed. {% endhint %} #### Signature ```typescript export async function updateCommandMetadata(metadata: { subtitle?: string | null }): Promise; ``` #### Example ```typescript import { updateCommandMetadata } from "@raycast/api"; async function fetchUnreadNotificationCount() { return 10; } export default async function Command() { const count = await fetchUnreadNotificationCount(); await updateCommandMetadata({ subtitle: `Unread Notifications: ${count}` }); } ``` #### Return A Promise that resolves when the command's metadata have been updated. ## Types ### LaunchContext Represents the passed context object of programmatic command launches. ### LaunchOptions A parameter object used to decide which command should be launched and what data (arguments, context) it should receive. #### IntraExtensionLaunchOptions The options that can be used when launching a command from the same extension. | Property | Description | Type | | :--- | :--- | :--- | | name* | Command name as defined in the extension's manifest | string | | type* | LaunchType.UserInitiated | | arguments | Optional object for the argument properties and values as defined in the extension's manifest, for example: `{ "argument1": "value1" }` | Arguments or null | | context | Arbitrary object for custom data that should be passed to the command and accessible as LaunchProps or null | | fallbackText | Optional string to send as fallback text to the command | string or null | #### InterExtensionLaunchOptions The options that can be used when launching a command from a different extension. | Property | Description | Type | | :--- | :--- | :--- | | extensionName* | When launching command from a different extension, the extension name (as defined in the extension's manifest) is necessary | string | | name* | Command name as defined in the extension's manifest | string | | ownerOrAuthorName* | When launching command from a different extension, the owner or author (as defined in the extension's manifest) is necessary | string | | type* | LaunchType.UserInitiated | | arguments | Optional object for the argument properties and values as defined in the extension's manifest, for example: `{ "argument1": "value1" }` | Arguments or null | | context | Arbitrary object for custom data that should be passed to the command and accessible as LaunchProps or null | | fallbackText | Optional string to send as fallback text to the command | string or null | # Environment The Environment APIs are useful to get context about the setup in which your command runs. You can get information about the extension and command itself as well as Raycast. Furthermore, a few paths are injected and are helpful to construct file paths that are related to the command's assets. ## API Reference ### environment Contains environment values such as the Raycast version, extension info, and paths. #### Example ```typescript import { environment } from "@raycast/api"; export default async function Command() { console.log(`Raycast version: ${environment.raycastVersion}`); console.log(`Owner or Author name: ${environment.ownerOrAuthorName}`); console.log(`Extension name: ${environment.extensionName}`); console.log(`Command name: ${environment.commandName}`); console.log(`Command mode: ${environment.commandMode}`); console.log(`Assets path: ${environment.assetsPath}`); console.log(`Support path: ${environment.supportPath}`); console.log(`Is development mode: ${environment.isDevelopment}`); console.log(`Appearance: ${environment.appearance}`); console.log(`Text size: ${environment.textSize}`); console.log(`LaunchType: ${environment.launchType}`); } ``` #### Properties | Property | Description | Type | | :--- | :--- | :--- | | appearance* | The appearance used by the Raycast application. | "light" or "dark" | | assetsPath* | The absolute path to the assets directory of the extension. | string | | commandMode* | The mode of the launched command, as specified in package.json | "no-view" or "view" or "menu-bar" | | commandName* | The name of the launched command, as specified in package.json | string | | extensionName* | The name of the extension, as specified in package.json | string | | isDevelopment* | Indicates whether the command is a development command (vs. an installed command from the Store). | boolean | | launchType* | The type of launch for the command (user initiated or background). | LaunchType | | ownerOrAuthorName* | The name of the extension owner (if any) or author, as specified in package.json | string | | raycastVersion* | The version of the main Raycast app | string | | supportPath* | The absolute path for the support directory of an extension. Use it to read and write files related to your extension or command. | string | | textSize* | The text size used by the Raycast application. | "medium" or "large" | | canAccess* | Returns whether the user has access to the given API. | (api: unknown) => boolean | ### environment.canAccess Checks whether the user can access a specific API or not. #### Signature ```typescript function canAccess(api: any): bool; ``` #### Example ```typescript import { AI, showHUD, environment } from "@raycast/api"; import fs from "fs"; export default async function main() { if (environment.canAccess(AI)) { const answer = await AI.ask("Suggest 5 jazz songs"); await Clipboard.copy(answer); } else { await showHUD("You don't have access :("); } } ``` #### Return A Boolean indicating whether the user running the command has access to the API. ### getSelectedFinderItems Gets the selected items from Finder. #### Signature ```typescript async function getSelectedFinderItems(): Promise; ``` #### Example ```typescript import { getSelectedFinderItems, showToast, Toast } from "@raycast/api"; export default async function Command() { try { const selectedItems = await getSelectedFinderItems(); console.log(selectedItems); } catch (error) { await showToast({ style: Toast.Style.Failure, title: "Cannot copy file path", message: String(error), }); } } ``` #### Return A Promise that resolves with the selected file system items. If Finder is not the frontmost application, the promise will be rejected. ### getSelectedText Gets the selected text of the frontmost application. #### Signature ```typescript async function getSelectedText(): Promise; ``` #### Example ```typescript import { getSelectedText, Clipboard, showToast, Toast } from "@raycast/api"; export default async function Command() { try { const selectedText = await getSelectedText(); const transformedText = selectedText.toUpperCase(); await Clipboard.paste(transformedText); } catch (error) { await showToast({ style: Toast.Style.Failure, title: "Cannot transform text", message: String(error), }); } } ``` #### Return A Promise that resolves with the selected text. If no text is selected in the frontmost application, the promise will be rejected. ## Types ### FileSystemItem Holds data about a File System item. Use the getSelectedFinderItems method to retrieve values. #### Properties | Property | Description | Type | | :--- | :--- | :--- | | path* | The path to the item | string | ### LaunchType Indicates the type of command launch. Use this to detect whether the command has been launched from the background. #### Enumeration members | Name | Description | | :------------ | :--------------------------------------------------------- | | UserInitiated | A regular launch through user interaction | | Background | Scheduled through an interval and launched from background | # Feedback Raycast has several ways to provide feedback to the user: - Toast _- when an asynchronous operation is happening or when an error is thrown_ - HUD _- to confirm an action worked after closing Raycast_ - Alert _- to ask for confirmation before taking an action_ # Alert When the user takes an important action (for example when irreversibly deleting something), you can ask for confirmation by using `confirmAlert`. ## API Reference ### confirmAlert Creates and shows a confirmation Alert with the given options. #### Signature ```typescript async function confirmAlert(options: Alert.Options): Promise; ``` #### Example ```typescript import { confirmAlert } from "@raycast/api"; export default async function Command() { if (await confirmAlert({ title: "Are you sure?" })) { console.log("confirmed"); // do something } else { console.log("canceled"); } } ``` #### Parameters | Name | Description | Type | | :--- | :--- | :--- | | options* | The options used to create the Alert. | Alert.Options | #### Return A Promise that resolves to a boolean when the user triggers one of the actions. It will be `true` for the primary Action, `false` for the dismiss Action. ## Types ### Alert.Options The options to create an Alert. #### Example ```typescript import { Alert, confirmAlert } from "@raycast/api"; export default async function Command() { const options: Alert.Options = { title: "Finished cooking", message: "Delicious pasta for lunch", primaryAction: { title: "Do something", onAction: () => { // while you can register a handler for an action, it's more elegant // to use the `if (await confirmAlert(...)) { ... }` pattern console.log("The alert action has been triggered"); }, }, }; await confirmAlert(options); } ``` #### Properties | Property | Description | Type | | :--- | :--- | :--- | | title* | The title of an alert. Displayed below the icon. | string | | dismissAction | The Action to dismiss the alert. There usually shouldn't be any side effects when the user takes this action. | Alert.ActionOptions | | icon | The icon of an alert to illustrate the action. Displayed on the top. | Image.ImageLike | | message | An additional message for an Alert. Useful to show more information, e.g. a confirmation message for a destructive action. | string | | primaryAction | The primary Action the user can take. | Alert.ActionOptions | | rememberUserChoice | If set to true, the Alert will also display a `Do not show this message again` checkbox. When checked, the answer is persisted and directly returned to the extension the next time the alert should be shown, without the user actually seeing the alert. | boolean | ### Alert.ActionOptions The options to create an Alert Action. #### Properties | Property | Description | Type | | :--- | :--- | :--- | | title* | The title of the action. | string | | style | The style of the action. | Alert.ActionStyle | | onAction | A callback called when the action is triggered. | () => void | ### Alert.ActionStyle Defines the visual style of an Action of the Alert. Use Alert.ActionStyle.Default for confirmations of a positive action. Use Alert.ActionStyle.Destructive. #### Enumeration members | Name | Value | | :---------- | :------------------------------------------------------- | | Default | | | Destructive | | | Cancel | | # HUD When the user takes an action that has the side effect of closing Raycast (for example when copying something in the Clipboard, you can use a HUD to confirm that the action worked properly. ## API Reference ### showHUD A HUD will automatically hide the main window and show a compact message at the bottom of the screen. #### Signature ```typescript async function showHUD( title: string, options?: { clearRootSearch?: boolean; popToRootType?: PopToRootType } ): Promise; ``` #### Example ```typescript import { showHUD } from "@raycast/api"; export default async function Command() { await showHUD("Hey there 👋"); } ``` `showHUD` closes the main window when called, so you can use the same options as `closeMainWindow`: ```typescript import { PopToRootType, showHUD } from "@raycast/api"; export default async function Command() { await showHUD("Hey there 👋", { clearRootSearch: true, popToRootType: PopToRootType.Immediate }); } ``` #### Parameters | Name | Description | Type | | :--- | :--- | :--- | | title* | The title that will be displayed in the HUD. | string | | options | Can be used to control the behaviour after closing the main window. | Object | | options.clearRootSearch | Clears the text in the root search bar and scrolls to the top | boolean | | options.popToRootType | Defines the pop to root behavior (PopToRootType | #### Return A Promise that resolves when the HUD is shown. # Toast When an asynchronous operation is happening or when an error is thrown, it's usually a good idea to keep the user informed about it. Toasts are made for that. Additionally, Toasts can have some actions associated to the action they are about. For example, you could provide a way to cancel an asynchronous operation, undo an action, or copy the stack trace of an error. ## API Reference ### showToast Creates and shows a Toast with the given options. #### Signature ```typescript async function showToast(options: Toast.Options): Promise; ``` #### Example ```typescript import { showToast, Toast } from "@raycast/api"; export default async function Command() { const success = false; if (success) { await showToast({ title: "Dinner is ready", message: "Pizza margherita" }); } else { await showToast({ style: Toast.Style.Failure, title: "Dinner isn't ready", message: "Pizza dropped on the floor", }); } } ``` When showing an animated Toast, you can later on update it: ```typescript import { showToast, Toast } from "@raycast/api"; import { setTimeout } from "timers/promises"; export default async function Command() { const toast = await showToast({ style: Toast.Style.Animated, title: "Uploading image", }); try { // upload the image await setTimeout(1000); toast.style = Toast.Style.Success; toast.title = "Uploaded image"; } catch (err) { toast.style = Toast.Style.Failure; toast.title = "Failed to upload image"; if (err instanceof Error) { toast.message = err.message; } } } ``` #### Parameters | Name | Description | Type | | :--- | :--- | :--- | | options* | The options to customize the Toast. | Alert.Options | #### Return A Promise that resolves with the shown Toast. The Toast can be used to change or hide it. ## Types ### Toast A Toast with a certain style, title, and message. Use showToast to create and show a Toast. #### Properties | Property | Description | Type | | :--- | :--- | :--- | | message* | An additional message for the Toast. Useful to show more information, e.g. an identifier of a newly created asset. | string | | primaryAction* | The primary Action the user can take when hovering on the Toast. | Alert.ActionOptions | | secondaryAction* | The secondary Action the user can take when hovering on the Toast. | Alert.ActionOptions | | style* | The style of a Toast. | Action.Style | | title* | The title of a Toast. Displayed on the top. | string | #### Methods | Name | Type | Description | | :--- | :---------------------------------- | :--------------- | | hide | () => Promise<void> | Hides the Toast. | | show | () => Promise<void> | Shows the Toast. | ### Toast.Options The options to create a Toast. #### Example ```typescript import { showToast, Toast } from "@raycast/api"; export default async function Command() { const options: Toast.Options = { style: Toast.Style.Success, title: "Finished cooking", message: "Delicious pasta for lunch", primaryAction: { title: "Do something", onAction: (toast) => { console.log("The toast action has been triggered"); toast.hide(); }, }, }; await showToast(options); } ``` #### Properties | Property | Description | Type | | :--- | :--- | :--- | | title* | The title of a Toast. Displayed on the top. | string | | message | An additional message for the Toast. Useful to show more information, e.g. an identifier of a newly created asset. | string | | primaryAction | The primary Action the user can take when hovering on the Toast. | Alert.ActionOptions | | secondaryAction | The secondary Action the user can take when hovering on the Toast. | Alert.ActionOptions | | style | The style of a Toast. | Action.Style | ### Toast.Style Defines the visual style of the Toast. Use Toast.Style.Success for displaying errors. Use Toast.Style.Animated when your Toast should be shown until a process is completed. You can hide it later by using Toast.hide or update the properties of an existing Toast. #### Enumeration members | Name | Value | | :------- | :--------------------------------------------- | | Animated | | | Success | | | Failure | | ### Toast.ActionOptions The options to create a Toast Action. #### Properties | Property | Description | Type | | :--- | :--- | :--- | | title* | The title of the action. | string | | onAction* | A callback called when the action is triggered. | (toast: Toast => void | | shortcut | The keyboard shortcut for the action. | Keyboard.Shortcut | # Keyboard The Keyboard APIs are useful to make your actions accessible via the keyboard shortcuts. Shortcuts help users to use your command without touching the mouse. ## Types ### Keyboard.Shortcut A keyboard shortcut is defined by one or more modifier keys (command, control, etc.) and a single key equivalent (a character or special key). See KeyModifier for supported values. #### Example ```typescript import { Action, ActionPanel, Detail, Keyboard } from "@raycast/api"; export default function Command() { return ( console.log("Go up")} /> console.log("Go down")} /> console.log("Go left")} /> console.log("Go right")} /> console.log("Open")} /> } /> ); } ``` #### Properties | Property | Description | Type | | :--- | :--- | :--- | | key* | The key of the keyboard shortcut. | Keyboard.KeyEquivalent | | modifiers* | The modifier keys of the keyboard shortcut. | Keyboard.KeyModifier[] | ### Keyboard.Shortcut.Common A collection of shortcuts that are commonly used throughout Raycast. Using them should help provide a more consistent experience and preserve muscle memory. | Name | Shortcut | | --------------- | --------- | | Copy | ⌘ + ⇧ + C | | CopyDeeplink | ⌘ + ⇧ + C | | CopyName | ⌘ + ⇧ + . | | CopyPath | ⌘ + ⇧ + , | | Duplicate | ⌘ + D | | Edit | ⌘ + E | | MoveDown | ⌘ + ⇧ + ↓ | | MoveUp | ⌘ + ⇧ + ↑ | | New | ⌘ + N | | Open | ⌘ + O | | OpenWith | ⌘ + ⇧ + O | | Pin | ⌘ + ⇧ + P | | Refresh | ⌘ + R | | Remove | ⌃ + X | | RemoveAll | ⌃ + ⇧ + X | | ToggleQuickLook | ⌘ + Y | ### Keyboard.KeyEquivalent ```typescript KeyEquivalent: "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" | "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "." | "," | ";" | "=" | "+" | "-" | "[" | "]" | "{" | "}" | "«" | "»" | "(" | ")" | "/" | "\\" | "'" | "`" | "§" | "^" | "@" | "$" | "return" | "delete" | "deleteForward" | "tab" | "arrowUp" | "arrowDown" | "arrowLeft" | "arrowRight" | "pageUp" | "pageDown" | "home" | "end" | "space" | "escape" | "enter" | "backspace"; ``` KeyEquivalent of a Shortcut ### Keyboard.KeyModifier ```typescript KeyModifier: "cmd" | "ctrl" | "opt" | "shift"; ``` Modifier of a Shortcut # Menu Bar Commands The `MenuBarExtra` component can be used to create commands which populate the [extras](https://developer.apple.com/design/human-interface-guidelines/components/system-experiences/the-menu-bar#menu-bar-commands) section of macOS' menu bar. ## Getting Started If you don't have an extension yet, follow the getting started guide and then return to this page. Now that your extension is ready, let's open its `package.json` file and add a new entry to its `commands` array, ensuring its `mode` property is set to `menu-bar`. For this guide, let's add the following: ```JSON { "name": "github-pull-requests", "title": "Pull Requests", "subtitle": "GitHub", "description": "See your GitHub pull requests at a glance", "mode": "menu-bar" }, ``` {% hint style="info" %} Check out the command properties entry in the manifest file documentation for more detailed information on each of those properties. {% endhint %} Create `github-pull-requests.tsx` in your extensions `src/` folder and add the following: ```typescript import { MenuBarExtra } from "@raycast/api"; export default function Command() { return ( { console.log("seen pull request clicked"); }} /> { console.log("unseen pull request clicked"); }} /> ); } ``` If your development server is running, the command should appear in your root search, and running the command should result in the `GitHub` icon appearing in your menu bar. {% hint style="info" %} macOS has the final say on whether a given menu bar extra is displayed. If you have a lot of items there, it is possible that the command we just ran doesn't show up. If that's the case, try to clear up some space in the menu bar, either by closing some of the items you don't need or by hiding them using [HiddenBar](https://github.com/dwarvesf/hidden), [Bartender](https://www.macbartender.com/), or similar apps. {% endhint %} Of course, our pull request command wouldn't be of that much use if we had to tell it to update itself every single time. To add background refresh to our command, we need to open the `package.json` file we modified earlier and add an `interval` key to the command configuration object: ```JSON { "name": "github-pull-requests", "title": "Pull Requests", "subtitle": "GitHub", "description": "See your GitHub pull requests at a glance", "mode": "menu-bar", "interval": "5m" } ``` Your root search should look similar to: Running it once should activate it to: ## Lifecycle Although `menu-bar` commands can result in items permanently showing up in the macOS menu bar, they are not long-lived processes. Instead, as with other commands, Raycast loads them into memory on demand, executes their code and then tries to unload them at the next convenient time. There are five distinct events that can result in a `menu-bar`'s item being placed in the menu bar, so let's walk through each one. ### From the root search Same as any other commands, `menu-bar` commands can be run directly from Raycast's root search. Eventually, they may result in a new item showing up in your menu bar (if you have enough room and if the command returns a `MenuBarExtra`), or in a previous item disappearing, if the command returns `null`. In this case, Raycast will load your command code, execute it, wait for the `MenuBarExtra`'s `isLoading` prop to switch to `false`, and unload the command. {% hint style="danger" %} If your command returns a `MenuBarExtra`, it _must_ either not set `isLoading` - in which case Raycast will render and immediately unload the command, or set it to `true` while it's performing an async task (such as an API call) and then set it to `false` once it's done. Same as above, Raycast will load the command code, execute it, wait for `MenuBarExtra`'s `isLoading` prop to switch to `false`, and then unload the command. {% endhint %} ### At a set interval If your `menu-bar` command also makes use of background refresh _and_ it has background refresh activated, Raycast will run the command at set intervals. In your command, you can use `environment.launchType` to check whether it is launched in the background or by the user. {% hint style="info" %} To ease testing, commands configured to run in the background have an extra action in development mode: {% endhint %} ### When the user clicks the command's icon / title in the menu bar One of the bigger differences to `view` or `no-view` commands is that `menu-bar` commands have an additional entry point: when the user clicks their item in the menu bar. If the item has a menu (i.e. `MenuBarExtra` provides at least one child), Raycast will load the command code, execute it and keep it in memory while the menu is open. When the menu closes (either by the user clicking outside, or by clicking a `MenuBarExtra.Item`), the command is then unloaded. ### When Raycast is restarted This case assumes that your command has run at least once, resulting in an item being placed in the menu bar. If that's the case, quitting and starting Raycast again should put the same item in your menu bar. However, that item will be restored from Raycast's database - _not_ by loading and executing the command. ### When a menu bar command is re-enabled in preferences This case should work the same as when Raycast is restarted. ## Best practices - make generous use of the Cache API in order to provide quick feedback and ensure action handlers work as expected - make sure you set `isLoading` to false when your command finishes executing - avoid setting long titles in `MenuBarExtra`, `MenuBarExtra.Submenu` or `MenuBarExtra.Item` - don't put identical `MenuBarExtra.Item`s at the same level (direct children of `MenuBarExtra` or in the same `Submenu`) as their `onAction` handlers will not be executed correctly ## API Reference ### MenuBarExtra Adds an item to the menu bar, optionally with a menu attached in case its `children` prop is non-empty. {% hint style="info" %} `menu-bar` commands don't always need to return a `MenuBarExtra`. Sometimes it makes sense to remove an item from the menu bar, in which case you can write your command logic to return `null` instead. {% endhint %} #### Example ```typescript import { Icon, MenuBarExtra, open } from "@raycast/api"; const data = { archivedBookmarks: [{ name: "Google Search", url: "www.google.com" }], newBookmarks: [{ name: "Raycast", url: "www.raycast.com" }], }; export default function Command() { return ( {data?.newBookmarks.map((bookmark) => ( open(bookmark.url)} /> ))} {data?.archivedBookmarks.map((bookmark) => ( open(bookmark.url)} /> ))} ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | children | `MenuBarExtra.Item`s, `MenuBarExtra.Submenu`s, `MenuBarExtra.Separator` or a mix of either. | React.ReactNode | - | | icon | The icon that is displayed in the menu bar. | Image.ImageLike | - | | isLoading | Indicates to Raycast that it should not unload the command, as it is still executing. If you set make use of `isLoading`, you need to make sure you set it to `false` at the end of the task you are executing (such as an API call), so Raycast can then unload the command. | boolean | `false` | | title | The string that is displayed in the menu bar. | string | - | | tooltip | A tooltip to display when the cursor hovers the item in the menu bar. | string | - | ### MenuBarExtra.Item An item in the MenuBarExtra. #### Example {% tabs %} {% tab title="ItemWithTitle.tsx" %} An item that only provides a `title` prop will be rendered as disabled. Use this to create section titles. ```typescript import { Icon, MenuBarExtra } from "@raycast/api"; export default function Command() { return ( ); } ``` {% endtab %} {% tab title="ItemWithTitleAndIcon.tsx" %} Similarly, an item that provides a `title` and an `icon` prop will also be rendered as disabled. ```typescript import { Icon, MenuBarExtra } from "@raycast/api"; export default function Command() { return ( ); } ``` {% endtab %} {% tab title="ItemWithAction.tsx" %} An item that provides an `onAction` prop alongside `title` (and optionally `icon`) will _not_ be rendered as disabled. When users click this item in the menu bar, the action handler will be executed. ```typescript import { Icon, MenuBarExtra, open } from "@raycast/api"; export default function Command() { return ( open("https://raycast.com")} /> ); } ``` {% endtab %} {% tab title="ItemWithAlternate.tsx" %} If an item provides another `MenuBarEtra.Item` via its `alternate`, prop, the second item will be shown then the user presses the ⌥ (opt) key. There are a few limitation: 1. The `alternate` item may not have a custom shortcut. Instead, it will inherit its parent's shortcut, with the addition of ⌥ (opt) as a modifier. 2. The `alternate` item may not also specify an alternate. 3. A parent item that provides an `alternate` may not use ⌥ (opt) as a modifier. ```typescript import { Icon, MenuBarExtra, open } from "@raycast/api"; export default function Command() { return ( open("https://raycast.com")} alternate={ open("https://raycast.com/store")} /> } /> ); } ``` {% endtab %} {% endtabs %} #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | title* | The main title displayed for this item. | string | - | | alternate | A MenuBarExtra.Item, string> | - | | icon | An optional icon for this item. | Image.ImageLike | - | | shortcut | A shortcut used to invoke this item when its parent menu is open. | Keyboard.Shortcut | - | | subtitle | The subtitle displayed for this item. | string | - | | tooltip | A tooltip to display when the cursor hovers the item. | string | - | | onAction | An action handler called when the user clicks the item. | (event: MenuBarExtra.ActionEvent => void | - | ### MenuBarExtra.Submenu `MenuBarExtra.Submenu`s reveal their items when people interact with them. They're a good way to group items that naturally belong together, but keep in mind that submenus add complexity to your interface - so use them sparingly! #### Example {% tabs %} {% tab title="Bookmarks.tsx" %} ```typescript import { Icon, MenuBarExtra, open } from "@raycast/api"; export default function Command() { return ( open("https://raycast.com")} /> open("https://github.com/pulls")} /> open("https://github.com/issues")} /> ); } ``` {% endtab %} {% tab title="DisabledSubmenu.tsx" %} Submenus with no children will show up as disabled. ```typescript import { Icon, MenuBarExtra, open } from "@raycast/api"; export default function Command() { return ( ); } ``` {% endtab %} {% endtabs %} #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | title* | The main title displayed for this submenu. | string | - | | children | `MenuBarExtra.Item`s, `MenuBarExtra.Submenu`s, `MenuBarExtra.Separator` or a mix of either. | React.ReactNode | - | | icon | An optional icon for this submenu. | Image.ImageLike | - | ### MenuBarExtra.Section An item to group related menu items. It has an optional title and a separator is added automatically between sections. #### Example ```typescript import { Icon, MenuBarExtra, open } from "@raycast/api"; const data = { archivedBookmarks: [{ name: "Google Search", url: "www.google.com" }], newBookmarks: [{ name: "Raycast", url: "www.raycast.com" }], }; export default function Command() { return ( {data?.newBookmarks.map((bookmark) => ( open(bookmark.url)} /> ))} {data?.archivedBookmarks.map((bookmark) => ( open(bookmark.url)} /> ))} ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | children | The item elements of the section. | React.ReactNode | - | | title | Title displayed above the section | string | - | ## Types ### MenuBarExtra.ActionEvent An interface describing Action events in callbacks. #### Properties | Property | Description | Type | | :--- | :--- | :--- | | type* | A type of the action event | "left-click" or "right-click" | #### Example ```typescript import { MenuBarExtra } from "@raycast/api"; export default function Command() { return ( console.log("Action Event Type", event.type)} /> ); } ``` # OAuth ## Prerequisites A Raycast extension can use OAuth for authorizing access to a provider's resources on the user's behalf. Since Raycast is a desktop app and the extensions are considered "public", we only support the [PKCE flow](https://datatracker.ietf.org/doc/html/rfc7636) (Proof Key for Code Exchange, pronounced “pixy”). This flow is the official recommendation for native clients that cannot keep a client secret. With PKCE, the client dynamically creates a secret and uses the secret again during code exchange, ensuring that only the client that performed the initial request can exchange the code for the access token (”proof of possession”). {% hint style="info" %} Providers such as Google, Twitter, GitLab, Spotify, Zoom, Asana or Dropbox are all PKCE-ready. However, if your provider doesn't support PKCE, you can use our [PKCE proxy](https://oauth.raycast.com). It allows extensions to securely use an OAuth flow without exposing any secret. {% endhint %} ## OAuth Flow The OAuth flow from an extension looks like this: 1. The extension initiates the OAuth flow and starts authorization 2. Raycast shows the OAuth overlay ("Connect to provider…") 3. The user opens the provider's consent page in the web browser 4. After the user consent, the provider redirects back to Raycast 5. Raycast opens the extension where authorization is completed When the flow is complete, the extension has received an access token from the provider and can perform API calls. The API provides functions for securely storing and retrieving token sets, so that an extension can check whether the user is already logged in and whether an expired access token needs to be refreshed. Raycast also automatically shows a logout preference. ## OAuth App You first need to register a new OAuth app with your provider. This is usually done in the provider's developer portal. After registering, you will receive a client ID. You also need to configure a redirect URI, see the next section. Note: Make sure to choose an app type that supports PKCE. Some providers still show you a client secret, which you don't need and should _not_ hardcode in the extension, or support PKCE only for certain types such as "desktop", "native" or "mobile" app types. ## Authorizing An extension can initiate the OAuth flow and authorize by using the methods on OAuth.PKCEClient. You can create a new client and configure it with a provider name, icon and description that will be shown in the OAuth overlay. You can also choose between different redirect methods; depending on which method you choose, you need to configure this value as redirect URI in your provider's registered OAuth app. (See the OAuth.RedirectMethod. ```typescript import { OAuth } from "@raycast/api"; const client = new OAuth.PKCEClient({ redirectMethod: OAuth.RedirectMethod.Web, providerName: "Twitter", providerIcon: "twitter-logo.png", description: "Connect your Twitter account…", }); ``` Next you create an authorization request with the authorization endpoint, client ID, and scope values. You receive all values from your provider's docs and when you register a new OAuth app. The returned AuthorizationRequest if you need to. ```typescript const authRequest = await client.authorizationRequest({ endpoint: "https://twitter.com/i/oauth2/authorize", clientId: "YourClientId", scope: "tweet.read users.read follows.read", }); ``` To get the authorization code needed for the token exchange, you call authorize with the request from the previous step. This call shows the Raycast OAuth overlay and provides the user with an option to open the consent page in the web browser. The authorize promise is resolved after the redirect back to Raycast and into the extension: ```typescript const { authorizationCode } = await client.authorize(authRequest); ``` {% hint style="info" %} When in development mode, make sure not to trigger auto-reloading (e.g. by saving a file) while you're testing an active OAuth authorization and redirect. This would cause an OAuth state mismatch when you're redirected back into the extension since the client would be reinitialized on reload. {% endhint %} Now that you have received the authorization code, you can exchange this code for an access token using your provider's token endpoint. This token exchange (and the following API calls) can be done with your preferred Node HTTP client library. Example using `node-fetch`: ```typescript async function fetchTokens(authRequest: OAuth.AuthorizationRequest, authCode: string): Promise { const params = new URLSearchParams(); params.append("client_id", "YourClientId"); params.append("code", authCode); params.append("code_verifier", authRequest.codeVerifier); params.append("grant_type", "authorization_code"); params.append("redirect_uri", authRequest.redirectURI); const response = await fetch("https://api.twitter.com/2/oauth2/token", { method: "POST", body: params, }); if (!response.ok) { console.error("fetch tokens error:", await response.text()); throw new Error(response.statusText); } return (await response.json()) as OAuth.TokenResponse; } ``` ## Token Storage The PKCE client exposes methods for storing, retrieving and deleting token sets. A TokenSet: ```typescript await client.setTokens(tokenResponse); ``` Once the token set is stored, Raycast will automatically show a logout preference for the extension. When the user logs out, the token set gets removed. The TokenSet also enables you to check whether the user is logged in before starting the authorization flow: ```typescript const tokenSet = await client.getTokens(); ``` ## Token Refresh Since access tokens usually expire, an extension should provide a way to refresh the access token, otherwise users would be logged out or see errors. Some providers require you to add an offline scope so that you get a refresh token. (Twitter, for example, needs the scope `offline.access` or it only returns an access token.) A basic refresh flow could look like this: ```typescript const tokenSet = await client.getTokens(); if (tokenSet?.accessToken) { if (tokenSet.refreshToken && tokenSet.isExpired()) { await client.setTokens(await refreshTokens(tokenSet.refreshToken)); } return; } // authorize... ``` This code would run before starting the authorization flow. It checks the presence of a token set to see whether the user is logged in and then checks whether there is a refresh token and the token set is expired (through the convenience method `isExpired()` on the TokenSet. If it is expired, the token is refreshed and updated in the token set. Example using `node-fetch`: ```typescript async function refreshTokens(refreshToken: string): Promise { const params = new URLSearchParams(); params.append("client_id", "YourClientId"); params.append("refresh_token", refreshToken); params.append("grant_type", "refresh_token"); const response = await fetch("https://api.twitter.com/2/oauth2/token", { method: "POST", body: params, }); if (!response.ok) { console.error("refresh tokens error:", await response.text()); throw new Error(response.statusText); } const tokenResponse = (await response.json()) as OAuth.TokenResponse; tokenResponse.refresh_token = tokenResponse.refresh_token ?? refreshToken; return tokenResponse; } ``` ## Examples We've provided [OAuth example integrations for Google, Twitter, and Dropbox](https://github.com/raycast/extensions/tree/main/examples/api-examples) that demonstrate the entire flow shown above. ## API Reference ### OAuth.PKCEClient Use OAuth.PKCEClient.Options to configure what's shown on the OAuth overlay. #### Signature ```typescript constructor(options: OAuth.PKCEClient.Options): OAuth.PKCEClient ``` #### Example ```typescript import { OAuth } from "@raycast/api"; const client = new OAuth.PKCEClient({ redirectMethod: OAuth.RedirectMethod.Web, providerName: "Twitter", providerIcon: "twitter-logo.png", description: "Connect your Twitter account…", }); ``` #### Methods | Method | | :----------------------------------------------------------------------------------------------------------------------------------------------- | | authorizationRequest(options: AuthorizationRequestOptions): Promise | | authorize(options: AuthorizationRequest \| AuthorizationOptions): Promise | | setTokens(options: TokenSetOptions \| TokenResponse): Promise | | getTokens(): Promise | | removeTokens(): Promise | ### OAuth.PKCEClient#authorizationRequest Creates an authorization request for the provided authorization endpoint, client ID, and scopes. You need to first create the authorization request before calling authorize. The generated code challenge for the PKCE request uses the S256 method. #### Signature ```typescript authorizationRequest(options: AuthorizationRequestOptions): Promise; ``` #### Example ```typescript const authRequest = await client.authorizationRequest({ endpoint: "https://twitter.com/i/oauth2/authorize", clientId: "YourClientId", scope: "tweet.read users.read follows.read", }); ``` #### Parameters | Name | Type | Description | | :---------------------------------------- | :----------------------------------------------------------------------------- | :---------------------------------------------------- | | options\* | AuthorizationRequestOptions | The options used to create the authorization request. | #### Return A promise for an AuthorizationRequest. ### OAuth.PKCEClient#authorize Starts the authorization and shows the OAuth overlay in Raycast. As parameter you can either directly use the returned request from authorizationRequest. Eventually the URL will be used to open the authorization page of the provider in the web browser. #### Signature ```typescript authorize(options: AuthorizationRequest | AuthorizationOptions): Promise; ``` #### Example ```typescript const { authorizationCode } = await client.authorize(authRequest); ``` #### Parameters | Name | Type | Description | | :---------------------------------------- | :---------------------------------------------------------------------------------------------------------------------- | :----------------------------- | | options\* | AuthorizationRequest | The options used to authorize. | #### Return A promise for an AuthorizationResponse, which contains the authorization code needed for the token exchange. The promise is resolved when the user was redirected back from the provider's authorization page to the Raycast extension. ### OAuth.PKCEClient#setTokens Securely stores a TokenSet. At a minimum, you need to set the `accessToken`, and typically you also set `refreshToken` and `isExpired`. Raycast automatically shows a logout preference for the extension when a token set was saved. If you want to make use of the convenience `isExpired()` method, the property `expiresIn` must be configured. #### Signature ```typescript setTokens(options: TokenSetOptions | TokenResponse): Promise; ``` #### Example ```typescript await client.setTokens(tokenResponse); ``` #### Parameters | Name | Type | Description | | :---------------------------------------- | :---------------------------------------------------------------------------------------------- | :--------------------------------------- | | options\* | TokenSetOptions | The options used to store the token set. | #### Return A promise that resolves when the token set has been stored. ### OAuth.PKCEClient#getTokens Retrieves the stored TokenSet for the client. You can use this to initially check whether the authorization flow should be initiated or the user is already logged in and you might have to refresh the access token. #### Signature ```typescript getTokens(): Promise; ``` #### Example ```typescript const tokenSet = await client.getTokens(); ``` #### Return A promise that resolves when the token set has been retrieved. ### OAuth.PKCEClient#removeTokens Removes the stored TokenSet for the client. Raycast automatically shows a logout preference that removes the token set. Use this method only if you need to provide an additional logout option in your extension or you want to remove the token set because of a migration. #### Signature ```typescript removeTokens(): Promise; ``` #### Example ```typescript await client.removeTokens(); ``` #### Return A promise that resolves when the token set has been removed. ## Types ### OAuth.PKCEClient.Options The options for creating a new PKCEClient. #### Properties | Property | Description | Type | | :--- | :--- | :--- | | providerName* | The name of the provider, displayed in the OAuth overlay. | string | | redirectMethod* | The redirect method for the OAuth flow. Make sure to set this to the correct method for the provider, see OAuth.RedirectMethod | | description | An optional description, shown in the OAuth overlay. You can use this to customize the message for the end user, for example for handling scope changes or other migrations. Raycast shows a default message if this is not configured. | string | | providerIcon | An icon displayed in the OAuth overlay. Make sure to provide at least a size of 64x64 pixels. | Image.ImageLike | | providerId | An optional ID for associating the client with a provider. Only set this if you use multiple different clients in your extension. | string | ### OAuth.RedirectMethod Defines the supported redirect methods for the OAuth flow. You can choose between web and app-scheme redirect methods, depending on what the provider requires when setting up the OAuth app. For examples on what redirect URI you need to configure, see the docs for each method. #### Enumeration members | Name | Value | | :----- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Web | Use this type for a redirect back to the Raycast website, which will then open the extension. In the OAuth app, configure `https://raycast.com/redirect?packageName=Extension`
(This is a static redirect URL for all extensions.)
If the provider does not accept query parameters in redirect URLs, you can alternatively use `https://raycast.com/redirect/extension` and then customize the AuthorizationRequest via its `extraParameters` property. For example add: `extraParameters: { "redirect_uri": "https://raycast.com/redirect/extension" }` | | App | Use this type for an app-scheme based redirect that directly opens Raycast. In the OAuth app, configure `raycast://oauth?package_name=Extension` | | AppURI | Use this type for a URI-style app scheme that directly opens Raycast. In the OAuth app, configure `com.raycast:/oauth?package_name=Extension`
(Note the single slash – Google, for example, would require this flavor for an OAuth app where the Bundle ID is `com.raycast`) | ### OAuth.AuthorizationRequestOptions The options for an authorization request via authorizationRequest. | Property | Description | Type | | :--- | :--- | :--- | | clientId* | The client ID of the configured OAuth app. | string | | endpoint* | The URL to the authorization endpoint for the OAuth provider. | string | | scope* | A space-delimited list of scopes for identifying the resources to access on the user's behalf. The scopes are typically shown to the user on the provider's consent screen in the browser. Note that some providers require the same scopes be configured in the registered OAuth app. | string | | extraParameters | Optional additional parameters for the authorization request. Note that some providers require additional parameters, for example to obtain long-lived refresh tokens. | Record<string, string> | ### OAuth.AuthorizationRequestURLParams Values of AuthorizationRequest. The PKCE client automatically generates the values for you and returns them for authorizationRequest | Property | Description | Type | | :--- | :--- | :--- | | codeChallenge* | The PKCE `code_challenge` value. | string | | codeVerifier* | The PKCE `code_verifier` value. | string | | redirectURI* | The OAuth `redirect_uri` value. | string | | state* | The OAuth `state` value. | string | ### OAuth.AuthorizationRequest The request returned by authorizationRequest. Can be used as direct input to authorize. | Property | Description | Type | | :--- | :--- | :--- | | codeChallenge* | The PKCE `code_challenge` value. | string | | codeVerifier* | The PKCE `code_verifier` value. | string | | redirectURI* | The OAuth `redirect_uri` value. | string | | state* | The OAuth `state` value. | string | | toURL* | Constructs the full authorization URL. | () => string | #### Methods | Name | Type | Description | | :------ | :------------------------ | :------------------------------------- | | toURL() | () => string | Constructs the full authorization URL. | ### OAuth.AuthorizationOptions Options for customizing authorize. You can use values from AuthorizationRequest to build your own URL. | Property | Description | Type | | :--- | :--- | :--- | | url* | The full authorization URL. | string | ### OAuth.AuthorizationResponse The response returned by authorize, containing the authorization code after the provider redirect. You can then exchange the authorization code for an access token using the provider's token endpoint. | Property | Description | Type | | :--- | :--- | :--- | | authorizationCode* | The authorization code from the OAuth provider. | string | ### OAuth.TokenSet Describes the TokenSet created from an OAuth provider's token response. The `accessToken` is the only required parameter but typically OAuth providers also return a refresh token, an expires value, and the scope. Securely store a token set via setTokens. | Property | Description | Type | | :--- | :--- | :--- | | accessToken* | The access token returned by an OAuth token request. | string | | updatedAt* | The date when the token set was stored via OAuth.PKCEClient.setTokens. | Date | | isExpired* | A convenience method for checking whether the access token has expired. The method factors in some seconds of "buffer", so it returns true a couple of seconds before the actual expiration time. This requires the `expiresIn` parameter to be set. | () => boolean | | expiresIn | An optional expires value (in seconds) returned by an OAuth token request. | number | | idToken | An optional id token returned by an identity request (e.g. /me, Open ID Connect). | string | | refreshToken | An optional refresh token returned by an OAuth token request. | string | | scope | The optional space-delimited list of scopes returned by an OAuth token request. You can use this to compare the currently stored access scopes against new access scopes the extension might require in a future version, and then ask the user to re-authorize with new scopes. | string | #### Methods | Name | Type | Description | | :---------- | :------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | isExpired() | () => boolean | A convenience method for checking whether the access token has expired. The method factors in some seconds of "buffer", so it returns true a couple of seconds before the actual expiration time. This requires the `expiresIn` parameter to be set. | ### OAuth.TokenSetOptions Options for a TokenSet. | Property | Description | Type | | :--- | :--- | :--- | | accessToken* | The access token returned by an OAuth token request. | string | | expiresIn | An optional expires value (in seconds) returned by an OAuth token request. | number | | idToken | An optional id token returned by an identity request (e.g. /me, Open ID Connect). | string | | refreshToken | An optional refresh token returned by an OAuth token request. | string | | scope | The optional scope value returned by an OAuth token request. | string | ### OAuth.TokenResponse Defines the standard JSON response for an OAuth token request. The response can be directly used to store a TokenSet. | Property | Description | Type | | :--- | :--- | :--- | | access_token* | The `access_token` value returned by an OAuth token request. | string | | expires_in | An optional `expires_in` value (in seconds) returned by an OAuth token request. | number | | id_token | An optional `id_token` value returned by an identity request (e.g. /me, Open ID Connect). | string | | refresh_token | An optional `refresh_token` value returned by an OAuth token request. | string | | scope | The optional `scope` value returned by an OAuth token request. | string | # Preferences Use the Preferences API to make your extension configurable. Preferences are configured in the manifest per command or shared in the context of an extension. Required preferences need to be set by the user before a command opens. They are a great way to make sure that the user of your extension has everything set up properly. ## API Reference ### getPreferenceValues A function to access the preference values that have been passed to the command. Each preference name is mapped to its value, and the defined default values are used as fallback values. #### Signature ```typescript function getPreferenceValues(): { [preferenceName: string]: any }; ``` #### Example ```typescript import { getPreferenceValues } from "@raycast/api"; interface Preferences { name: string; bodyWeight?: string; bodyHeight?: string; } export default async function Command() { const preferences = getPreferenceValues(); console.log(preferences); } ``` #### Return An object with the preference names as property key and the typed value as property value. Depending on the type of the preference, the type of its value will be different. | Preference type | Value type | | :--------------------- | :----------------------------------------------------- | | textfield | string | | password | string | | checkbox | boolean | | dropdown | string | | appPicker | Application | | file | string | | directory | string | ### openExtensionPreferences Opens the extension's preferences screen. #### Signature ```typescript export declare function openExtensionPreferences(): Promise; ``` #### Example ```typescript import { ActionPanel, Action, Detail, openExtensionPreferences } from "@raycast/api"; export default function Command() { const markdown = "API key incorrect. Please update it in extension preferences and try again."; return ( } /> ); } ``` #### Return A Promise that resolves when the extensions preferences screen is opened. ### openCommandPreferences Opens the command's preferences screen. #### Signature ```typescript export declare function openCommandPreferences(): Promise; ``` #### Example ```typescript import { ActionPanel, Action, Detail, openCommandPreferences } from "@raycast/api"; export default function Command() { const markdown = "API key incorrect. Please update it in command preferences and try again."; return ( } /> ); } ``` #### Return A Promise that resolves when the command's preferences screen is opened. ## Types ### Preferences A command receives the values of its preferences via the `getPreferenceValues` function. It is an object with the preferences' `name` as keys and their values as the property's values. Depending on the type of the preference, the type of its value will be different. | Preference type | Value type | | :--------------------- | :----------------------------------------------------- | | textfield | string | | password | string | | checkbox | boolean | | dropdown | string | | appPicker | Application | | file | string | | directory | string | {% hint style="info" %} Raycast provides a global TypeScript namespace called `Preferences` which contains the types of the preferences of all the commands of the extension. For example, if a command named `show-todos` has some preferences, its `getPreferenceValues`'s return type can be specified with `getPreferenceValues()`. This will make sure that the types used in the command stay in sync with the manifest. {% endhint %} # Storage The storage APIs can be used to store data in Raycast's local encrypted database. All commands in an extension have shared access to the stored data. Extensions can _not_ access the storage of other extensions. Values can be managed through functions such as `LocalStorage.getItem`. A typical use case is storing user-related data, for example entered todos. {% hint style="info" %} The API is not meant to store large amounts of data. For this, use [Node's built-in APIs to write files](https://nodejs.org/en/learn/manipulating-files/writing-files-with-nodejs), e.g. to the extension's support directory. {% endhint %} ## API Reference ### LocalStorage.getItem Retrieve the stored value for the given key. #### Signature ```typescript async function getItem(key: string): Promise; ``` #### Example ```typescript import { LocalStorage } from "@raycast/api"; export default async function Command() { await LocalStorage.setItem("favorite-fruit", "apple"); const item = await LocalStorage.getItem("favorite-fruit"); console.log(item); } ``` #### Parameters | Name | Description | Type | | :--- | :--- | :--- | | key* | The key you want to retrieve the value of. | string | #### Return A Promise that resolves with the stored value for the given key. If the key does not exist, `undefined` is returned. ### LocalStorage.setItem Stores a value for the given key. #### Signature ```typescript async function setItem(key: string, value: Value): Promise; ``` #### Example ```typescript import { LocalStorage } from "@raycast/api"; export default async function Command() { await LocalStorage.setItem("favorite-fruit", "apple"); const item = await LocalStorage.getItem("favorite-fruit"); console.log(item); } ``` #### Parameters | Name | Description | Type | | :--- | :--- | :--- | | key* | The key you want to create or update the value of. | string | | value* | The value you want to create or update for the given key. | LocalStorage.Value | #### Return A Promise that resolves when the value is stored. ### LocalStorage.removeItem Removes the stored value for the given key. #### Signature ```typescript async function removeItem(key: string): Promise; ``` #### Example ```typescript import { LocalStorage } from "@raycast/api"; export default async function Command() { await LocalStorage.setItem("favorite-fruit", "apple"); console.log(await LocalStorage.getItem("favorite-fruit")); await LocalStorage.removeItem("favorite-fruit"); console.log(await LocalStorage.getItem("favorite-fruit")); } ``` #### Parameters | Name | Description | Type | | :--- | :--- | :--- | | key* | The key you want to remove the value of. | string | #### Return A Promise that resolves when the value is removed. ### LocalStorage.allItems Retrieve all stored values in the local storage of an extension. #### Signature ```typescript async function allItems(): Promise; ``` #### Example ```typescript import { LocalStorage } from "@raycast/api"; interface Values { todo: string; priority: number; } export default async function Command() { const items = await LocalStorage.allItems(); console.log(`Local storage item count: ${Object.entries(items).length}`); } ``` #### Return A Promise that resolves with an object containing all Values. ### LocalStorage.clear Removes all stored values of an extension. #### Signature ```typescript async function clear(): Promise; ``` #### Example ```typescript import { LocalStorage } from "@raycast/api"; export default async function Command() { await LocalStorage.clear(); } ``` #### Return A Promise that resolves when all values are removed. ## Types ### LocalStorage.Values Values of local storage items. For type-safe values, you can define your own interface. Use the keys of the local storage items as the property names. #### Properties | Name | Type | Description | | :------------ | :--------------- | :-------------------------------------- | | [key: string] | any | The local storage value of a given key. | ### LocalStorage.Value ```typescript Value: string | number | boolean; ``` Supported storage value types. #### Example ```typescript import { LocalStorage } from "@raycast/api"; export default async function Command() { // String await LocalStorage.setItem("favorite-fruit", "cherry"); // Number await LocalStorage.setItem("fruit-basket-count", 3); // Boolean await LocalStorage.setItem("fruit-eaten-today", true); } ``` # User Interface Raycast uses React for its user interface declaration and renders the supported elements to our native UI. The API comes with a set of UI components that you can use to build your extensions. Think of it as a design system. The high-level components are the following: - List to show multiple similar items, f.e. a list of your open todos. - Grid similar to a List but with more legroom to show an image for each item, f.e. a collection of icons. - Detail to present more information, f.e. the details of a GitHub pull request. - Form to create new content, f.e. filing a bug report. Each component can provide interaction via an ActionPanel. Shortcuts allow users to use Raycast without using their mouse. ## Rendering To render a user interface, you need to do the following: - Set the `mode` to `view` in the `package.json` manifest file - Export a React component from your command entry file As a general rule of thumb, you should render something as quickly as possible. This guarantees that your command feels responsive. If you don't have data available to show, you can set the `isLoading` prop to `true` on top-level components such as ``. It shows a loading indicator at the top of Raycast. Here is an example that shows a loading indicator for 2 seconds after the command got launched: ```typescript import { List } from "@raycast/api"; import { useEffect, useState } from "react"; export default function Command() { const [isLoading, setIsLoading] = useState(true); useEffect(() => { setTimeout(() => setIsLoading(false), 2000); }, []); return {/* Render your data */}; } ``` # Action Panel ## API Reference ### ActionPanel Exposes a list of actions that can be performed by the user. Often items are context-aware, e.g., based on the selected list item. Actions can be grouped into semantic sections and can have keyboard shortcuts assigned. The first and second action become the primary and secondary action. They automatically get the default keyboard shortcuts assigned. In List it's `⌘` `↵` for the primary and `⌘` `⇧` `↵` for the secondary. Keep in mind that while you can specify an alternative shortcut for the primary and secondary actions, it won't be displayed in the Action Panel. #### Example ```typescript import { ActionPanel, Action, List } from "@raycast/api"; export default function Command() { return ( } /> ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | children | Sections or Actions. If Action | - | | title | The title displayed at the top of the panel | string | - | ### ActionPanel.Section A group of visually separated items. Use sections when the ActionPanel contains a lot of actions to help guide the user to related actions. For example, create a section for all copy actions. #### Example ```typescript import { ActionPanel, Action, List } from "@raycast/api"; export default function Command() { return ( console.log("Close PR #1")} /> } /> ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | children | The item elements of the section. | ActionPanel.Section.Children | - | | title | Title displayed above the section | string | - | ### ActionPanel.Submenu A very specific action that replaces the current ActionPanel with its children when selected. This is handy when an action needs to select from a range of options. For example, to add a label to a GitHub pull request or an assignee to a todo. #### Example ```typescript import { Action, ActionPanel, Color, Icon, List } from "@raycast/api"; export default function Command() { return ( console.log("Add bug label")} /> console.log("Add enhancement label")} /> console.log("Add help wanted label")} /> } /> ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | title* | The title displayed for submenu. | string | - | | autoFocus | Indicates whether the ActionPanel.Submenu should be focused automatically when the parent ActionPanel (or Actionpanel.Submenu) opens. | boolean | - | | children | Items of the submenu. | ActionPanel.Submenu.Children | - | | 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. | | icon | The icon displayed for the submenu. | Image.ImageLike | - | | isLoading | Indicates whether a loading indicator should be shown or hidden next to the search bar | boolean | `false` | | shortcut | The keyboard shortcut for the submenu. | Keyboard.Shortcut | - | | 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` | | onOpen | Callback that is triggered when the Submenu is opened. | () => void | - | | onSearchTextChange | Callback triggered when the search bar text changes. | (text: string) => void | - | ## Types ### ActionPanel.Children ```typescript ActionPanel.Children: ActionPanel.Section | ActionPanel.Section[] | ActionPanel.Section.Children | null ``` Supported children for the ActionPanel component. ### ActionPanel.Section.Children ```typescript ActionPanel.Section.Children: Action | Action[] | ReactElement | ReactElement[] | null ``` Supported children for the ActionPanel.Section component. ### ActionPanel.Submenu.Children ```typescript ActionPanel.Children: ActionPanel.Section | ActionPanel.Section[] | ActionPanel.Section.Children | null ``` Supported children for the ActionPanel.Submenu component. # Actions Our API includes a few built-in actions that can be used for common interactions, such as opening a link or copying some content to the clipboard. By using them, you make sure to follow our human interface guidelines. If you need something custom, use the `Action` component. All built-in actions are just abstractions on top of it. ## API Reference ### Action A context-specific action that can be performed by the user. Assign keyboard shortcuts to items to make it easier for users to perform frequently used actions. #### Example ```typescript import { ActionPanel, Action, List } from "@raycast/api"; export default function Command() { return ( console.log("Close PR #1")} /> } /> ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | title* | The title displayed for the Action. | string | - | | autoFocus | Indicates whether the Action should be focused automatically when the parent ActionPanel (or Actionpanel.Submenu) opens. | boolean | - | | icon | The icon displayed for the Action. | Image.ImageLike | - | | shortcut | The keyboard shortcut for the Action. | Keyboard.Shortcut | - | | style | Defines the visual style of the Action. | Alert.ActionStyle | | onAction | Callback that is triggered when the Action is selected. | () => void | - | ### Action.CopyToClipboard Action that copies the content to the clipboard. The main window is closed, and a HUD is shown after the content was copied to the clipboard. #### Example ```typescript import { ActionPanel, Action, Detail } from "@raycast/api"; export default function Command() { return ( } /> ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | content* | The contents that will be copied to the clipboard. | string or number or Clipboard.Content | - | | concealed | Indicates whether the content be treated as confidential. If `true`, it will not be recorded in the Clipboard History. | boolean | `false` | | icon | A optional icon displayed for the Action. | Image.ImageLike | | shortcut | The keyboard shortcut for the Action. | Keyboard.Shortcut | - | | title | An optional title for the Action. | string | `"Copy to Clipboard"` | | onCopy | Callback when the content was copied to clipboard. | (content: string \| number \| Clipboard.Content => void | - | ### Action.Open An action to open a file or folder with a specific application, just as if you had double-clicked the file's icon. The main window is closed after the file is opened. #### Example ```typescript import { ActionPanel, Detail, Action } from "@raycast/api"; export default function Command() { return ( } /> ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | target* | The file, folder or URL to open. | string | - | | title* | The title for the Action. | string | - | | application | The application name to use for opening the file. | string or Application | - | | icon | The icon displayed for the Action. | Image.ImageLike | | shortcut | The keyboard shortcut for the Action. | Keyboard.Shortcut | - | | onOpen | Callback when the file or folder was opened. | (target: string) => void | - | ### Action.OpenInBrowser Action that opens a URL in the default browser. The main window is closed after the URL is opened in the browser. #### Example ```typescript import { ActionPanel, Detail, Action } from "@raycast/api"; export default function Command() { return ( } /> ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | url* | The URL to open. | string | - | | icon | The icon displayed for the Action. | Image.ImageLike | | shortcut | The optional keyboard shortcut for the Action. | Keyboard.Shortcut | - | | title | An optional title for the Action. | string | `"Open in Browser"` | | onOpen | Callback when the URL was opened in the browser. | (url: string) => void | - | ### Action.OpenWith Action that opens a file or URL with a specific application. The action opens a sub-menu with all applications that can open the file or URL. The main window is closed after the item is opened in the specified application. #### Example ```typescript import { ActionPanel, Detail, Action } from "@raycast/api"; import { homedir } from "os"; const DESKTOP_DIR = `${homedir()}/Desktop`; export default function Command() { return ( } /> ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | path* | The path to open. | string | - | | icon | The icon displayed for the Action. | Image.ImageLike | | shortcut | The keyboard shortcut for the Action. | Keyboard.Shortcut | - | | title | The title for the Action. | string | `"Open With"` | | onOpen | Callback when the file or folder was opened. | (path: string) => void | - | ### Action.Paste Action that pastes the content to the front-most applications. The main window is closed after the content is pasted to the front-most application. #### Example ```typescript import { ActionPanel, Detail, Action } from "@raycast/api"; export default function Command() { return ( } /> ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | content* | The contents that will be pasted to the frontmost application. | string or number or Clipboard.Content | - | | icon | The icon displayed for the Action. | Image.ImageLike | | shortcut | The keyboard shortcut for the Action. | Keyboard.Shortcut | - | | title | An optional title for the Action. | string | `"Paste in Active App"` | | onPaste | Callback when the content was pasted into the front-most application. | (content: string \| number \| Clipboard.Content => void | - | ### Action.Push Action that pushes a new view to the navigation stack. #### Example ```typescript import { ActionPanel, Detail, Action } from "@raycast/api"; function Ping() { return ( } /> } /> ); } function Pong() { return ; } export default function Command() { return ; } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | target* | The target view that will be pushed to the navigation stack. | React.ReactNode | - | | title* | The title displayed for the Action. | string | - | | icon | The icon displayed for the Action. | Image.ImageLike | - | | shortcut | The keyboard shortcut for the Action. | Keyboard.Shortcut | - | | onPop | Callback when the target view will be popped. | () => void | - | | onPush | Callback when the target view was pushed. | () => void | - | ### Action.ShowInFinder Action that shows a file or folder in the Finder. The main window is closed after the file or folder is revealed in the Finder. #### Example ```typescript import { ActionPanel, Detail, Action } from "@raycast/api"; import { homedir } from "os"; const DOWNLOADS_DIR = `${homedir()}/Downloads`; export default function Command() { return ( } /> ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | path* | The path to open. | PathLike | - | | icon | A optional icon displayed for the Action. | Image.ImageLike | | shortcut | The keyboard shortcut for the Action. | Keyboard.Shortcut | - | | title | An optional title for the Action. | string | `"Show in Finder"` | | onShow | Callback when the file or folder was shown in the Finder. | (path: PathLike => void | - | ### Action.SubmitForm Action that adds a submit handler for capturing form values. #### Example ```typescript import { ActionPanel, Form, Action } from "@raycast/api"; export default function Command() { return (
console.log(values)} /> } > ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | icon | The icon displayed for the Action. | Image.ImageLike | - | | shortcut | The keyboard shortcut for the Action. | Keyboard.Shortcut | - | | style | Defines the visual style of the Action. | Alert.ActionStyle | | title | The title displayed for the Action. | string | `"Submit Form"` | | onSubmit | Callback when the Form was submitted. The handler receives a the values object containing the user input. | (input: Form.Values => boolean \| void \| Promise<boolean \| void> | - | ### Action.Trash Action that moves a file or folder to the Trash. #### Example ```typescript import { ActionPanel, Detail, Action } from "@raycast/api"; import { homedir } from "os"; const FILE = `${homedir()}/Downloads/get-rid-of-me.txt`; export default function Command() { return ( } /> ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | paths* | The item or items to move to the trash. | PathLike[] | - | | icon | A optional icon displayed for the Action. | Image.ImageLike | | shortcut | The optional keyboard shortcut for the Action. | Keyboard.Shortcut | - | | title | An optional title for the Action. | string | `"Move to Trash"` | | onTrash | Callback when all items were moved to the trash. | (paths: PathLike => void | - | ### Action.CreateSnippet Action that navigates to the the Create Snippet command with some or all of the fields prefilled. #### Example ```typescript import { ActionPanel, Detail, Action } from "@raycast/api"; export default function Command() { return ( } /> ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | snippet* | | Snippet | - | | icon | A optional icon displayed for the Action. See Image.ImageLike | - | | shortcut | The keyboard shortcut for the Action. | Keyboard.Shortcut | - | | title | An optional title for the Action. | string | - | ### Action.CreateQuicklink Action that navigates to the the Create Quicklink command with some or all of the fields prefilled. #### Example ```typescript import { ActionPanel, Detail, Action } from "@raycast/api"; export default function Command() { return ( } /> ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | quicklink* | The Quicklink | - | | icon | A optional icon displayed for the Action. See Image.ImageLike | - | | shortcut | The keyboard shortcut for the Action. | Keyboard.Shortcut | - | | title | An optional title for the Action. | string | - | ### Action.ToggleQuickLook Action that toggles the Quick Look to preview a file. #### Example ```typescript import { ActionPanel, List, Action } from "@raycast/api"; export default function Command() { return ( } /> ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | icon | The icon displayed for the Action. | Image.ImageLike | | shortcut | The keyboard shortcut for the Action. | Keyboard.Shortcut | - | | title | The title for the Action. | string | `"Quick Look"` | ### Action.PickDate Action to pick a date. #### Example ```typescript import { ActionPanel, List, Action } from "@raycast/api"; export default function Command() { return ( } /> ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | title* | A title for the Action. | string | - | | onChange* | Callback when the Date was picked | (date: Date) => void | - | | icon | A optional icon displayed for the Action. | Image.ImageLike | | max | The maximum date (inclusive) allowed for selection. | Date | - | | min | The minimum date (inclusive) allowed for selection. | Date | - | | shortcut | The keyboard shortcut for the Action. | Keyboard.Shortcut | - | | type | Indicates what types of date components can be picked | Action.PickDate.Type | - | ## Types ### Snippet #### Properties | Property | Description | Type | | :--- | :--- | :--- | | text* | The snippet contents. | string | | keyword | The keyword to trigger the snippet. | string | | name | The snippet name. | string | ### Quicklink #### Properties | Property | Description | Type | | :--- | :--- | :--- | | link* | The URL or file path, optionally including placeholders such as in "https://google.com/search?q=\{Query\}" | string | | application | The application that the quicklink should be opened in. | string or Application | | icon | The icon to display for the quicklink. | Icon | | name | The quicklink name | string | ### Action.Style Defines the visual style of the Action. Use Action.Style.Regular for displaying a regular actions. Use Action.Style.Destructive when your action has something that user should be careful about. Use the confirmation Alert if the action is doing something that user cannot revert. ### Action.PickDate.Type The types of date components the user can pick with an `Action.PickDate`. #### Enumeration members | Name | Description | | -------- | ---------------------------------------------------------------- | | DateTime | Hour and second can be picked in addition to year, month and day | | Date | Only year, month, and day can be picked | ### Action.PickDate.isFullDay A method that determines if a given date represents a full day or a specific time. ```tsx import { ActionPanel, List, Action } from "@raycast/api"; export default function Command() { return ( { if (Action.PickDate.isFullDay(values.reminderDate)) { // the event is for a full day } else { // the event is at a specific time } }} /> } /> ); } ``` # Colors Anywhere you can pass a color in a component prop, you can pass either: - A standard Color - A Dynamic Color - A Raw Color ## API Reference ### Color The standard colors. Use those colors for consistency. The colors automatically adapt to the Raycast theme (light or dark). #### Example ```typescript import { Color, Icon, List } from "@raycast/api"; export default function Command() { return ( ); } ``` #### Enumeration members | Name | Dark Theme | Light Theme | | :------------ | :-------------------------------------------------------- | :--------------------------------------------------- | | Blue | | | Green | | | Magenta | | | Orange | | | Purple | | | Red | | | Yellow | | | PrimaryText | | | SecondaryText | | ## Types ### Color.ColorLike ```typescript ColorLike: Color | Color.Dynamic | Color.Raw; ``` Union type for the supported color types. When using a Raw Color. However, we recommend leaving color adjustment on, unless your extension depends on exact color reproduction. #### Example ```typescript import { Color, Icon, List } from "@raycast/api"; export default function Command() { return ( ); } ``` ### Color.Dynamic A dynamic color applies different colors depending on the active Raycast theme. When using a Dynamic Color, it will be adjusted to achieve high contrast with the Raycast user interface. To disable color adjustment, you can set the `adjustContrast` property to `false`. However, we recommend leaving color adjustment on, unless your extension depends on exact color reproduction. #### Example ```typescript import { Icon, List } from "@raycast/api"; export default function Command() { return ( ); } ``` #### Properties | Property | Description | Type | | :--- | :--- | :--- | | dark* | The color which is used in dark theme. | string | | light* | The color which is used in light theme. | string | | adjustContrast | Enables dynamic contrast adjustment for light and dark theme color. | boolean | ### Color.Raw A color can also be a simple string. You can use any of the following color formats: - HEX, e.g `#FF0000` - Short HEX, e.g. `#F00` - RGBA, e.g. `rgb(255, 0, 0)` - RGBA Percentage, e.g. `rgb(255, 0, 0, 1.0)` - HSL, e.g. `hsla(200, 20%, 33%, 0.2)` - Keywords, e.g. `red` # Detail ## API Reference ### Detail Renders a markdown ([CommonMark](https://commonmark.org)) string with an optional metadata panel. Typically used as a standalone view or when navigating from a List. #### Example {% tabs %} {% tab title="Render a markdown string" %} ```typescript import { Detail } from "@raycast/api"; export default function Command() { return ; } ``` {% endtab %} {% tab title="Render an image from the assets directory" %} ```typescript import { Detail } from "@raycast/api"; export default function Command() { return ; } ``` {% endtab %} {% endtabs %} #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | actions | A reference to an ActionPanel. | React.ReactNode | - | | isLoading | Indicates whether a loading bar should be shown or hidden below the search bar | boolean | `false` | | markdown | The CommonMark string to be rendered. | string | - | | metadata | The `Detail.Metadata` to be rendered in the right side area | React.ReactNode | - | | navigationTitle | The main title for that view displayed in Raycast | string | Command title | {% hint style="info" %} You can specify custom image dimensions by adding a `raycast-width` and `raycast-height` query string to the markdown image. For example: `!Image Title` You can also specify a tint color to apply to an markdown image by adding a `raycast-tint-color` query string. For example: `!Image Title` {% endhint %} {% hint style="info" %} You can now render [LaTeX](https://www.latex-project.org) in the markdown. We support the following delimiters: - Inline math: `\(...\)` and `\begin{math}...\end{math}` - Display math: `\[...\]`, `$$...$$` and `\begin{equation}...\end{equation}` {% endhint %} ### Detail.Metadata A Metadata view that will be shown in the right-hand-side of the `Detail`. Use it to display additional structured data about the main content shown in the `Detail` view. #### Example ```typescript import { Detail } from "@raycast/api"; // Define markdown here to prevent unwanted indentation. const markdown = ` # Pikachu ![](https://assets.pokemon.com/assets/cms2/img/pokedex/full/025.png) Pikachu that can generate powerful electricity have cheek sacs that are extra soft and super stretchy. `; export default function Main() { return ( } /> ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | children* | The elements of the Metadata view. | React.ReactNode | - | ### Detail.Metadata.Label A single value with an optional icon. #### Example ```typescript import { Detail } from "@raycast/api"; // Define markdown here to prevent unwanted indentation. const markdown = ` # Pikachu ![](https://assets.pokemon.com/assets/cms2/img/pokedex/full/025.png) Pikachu that can generate powerful electricity have cheek sacs that are extra soft and super stretchy. `; export default function Main() { return ( } /> ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | title* | The title of the item. | string | - | | icon | An icon to illustrate the value of the item. | Image.ImageLike | - | | text | The text value of the item. Specifying `color` will display the text in the provided color. Defaults to Color.SecondaryText; value: string } | - | ### Detail.Metadata.Link An item to display a link. #### Example ```typescript import { Detail } from "@raycast/api"; // Define markdown here to prevent unwanted indentation. const markdown = ` # Pikachu ![](https://assets.pokemon.com/assets/cms2/img/pokedex/full/025.png) Pikachu that can generate powerful electricity have cheek sacs that are extra soft and super stretchy. `; export default function Main() { return ( } /> ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | target* | The target of the link. | string | - | | text* | The text value of the item. | string | - | | title* | The title shown above the item. | string | - | ### Detail.Metadata.TagList A list of `Tags` displayed in a row. #### Example ```typescript import { Detail } from "@raycast/api"; // Define markdown here to prevent unwanted indentation. const markdown = ` # Pikachu ![](https://assets.pokemon.com/assets/cms2/img/pokedex/full/025.png) Pikachu that can generate powerful electricity have cheek sacs that are extra soft and super stretchy. `; export default function Main() { return ( } /> ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | children* | The tags contained in the TagList. | React.ReactNode | - | | title* | The title shown above the item. | string | - | ### Detail.Metadata.TagList.Item A Tag in a `Detail.Metadata.TagList`. #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | color | Changes the text color to the provided color and sets a transparent background with the same color. | Color.ColorLike | - | | icon | The optional icon tag icon. Required if the tag has no text. | Image.ImageLike | - | | text | The optional tag text. Required if the tag has no icon. | string | - | | onAction | Callback that is triggered when the item is clicked. | () => void | - | ### Detail.Metadata.Separator A metadata item that shows a separator line. Use it for grouping and visually separating metadata items. ```typescript import { Detail } from "@raycast/api"; // Define markdown here to prevent unwanted indentation. const markdown = ` # Pikachu ![](https://assets.pokemon.com/assets/cms2/img/pokedex/full/025.png) Pikachu that can generate powerful electricity have cheek sacs that are extra soft and super stretchy. `; export default function Main() { return ( } /> ); } ``` # Form Our `Form` component provides great user experience to collect some data from a user and submit it for extensions needs. ## Two Types of Items: Controlled vs. Uncontrolled 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. ## Validation 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. The useForm utils hook nicely wraps this behaviour and is the recommended way to do deal with validations. {% hint style="info" %} Keep in mind that if the Form has any errors, the `Action.SubmitForm` `onSubmit` callback won't be triggered. {% endhint %} #### Example {% tabs %} {% tab title="FormValidationWithUtils.tsx" %} ```tsx import { Action, ActionPanel, Form, showToast, Toast } from "@raycast/api"; import { useForm, FormValidation } from "@raycast/utils"; interface SignUpFormValues { name: string; password: string; } export default function Command() { const { handleSubmit, itemProps } = useForm({ onSubmit(values) { showToast({ style: Toast.Style.Success, title: "Yay!", message: `${values.name} account created`, }); }, validation: { name: FormValidation.Required, password: (value) => { if (value && value.length < 8) { return "Password must be at least 8 symbols"; } else if (!value) { return "The item is required"; } }, }, }); return (
} > ); } ``` {% endtab %} {% tab title="FormValidationWithoutUtils.tsx" %} ```typescript import { Form } from "@raycast/api"; import { useState } from "react"; export default function Command() { const [nameError, setNameError] = useState(); const [passwordError, setPasswordError] = useState(); function dropNameErrorIfNeeded() { if (nameError && nameError.length > 0) { setNameError(undefined); } } function dropPasswordErrorIfNeeded() { if (passwordError && passwordError.length > 0) { setPasswordError(undefined); } } return (
{ if (event.target.value?.length == 0) { setNameError("The field should't be empty!"); } else { dropNameErrorIfNeeded(); } }} /> { 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!"); } }} /> ); } function validatePassword(value: string): boolean { return value.length >= 8; } ``` {% endtab %} {% endtabs %} ## Drafts 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`. {% hint style="info" %} - Drafts for forms nested in navigation are not supported yet. In this case, you will see a warning about it. - Drafts won't preserve the `Form.Password`'s values. - Drafts will be dropped once `Action.SubmitForm` is triggered. - If you call `popToRoot()`, drafts won't be preserved or updated. {% endhint %} #### Example {% tabs %} {% tab title="Uncontrolled Form" %} ```typescript 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 (
{ console.log("onSubmit", values); popToRoot(); }} /> } > ); } ``` {% endtab %} {% tab title="Controlled Form" %} ```typescript 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(draftValues?.title || ""); const [description, setDescription] = useState(draftValues?.description || ""); const [dueDate, setDueDate] = useState(draftValues?.dueDate || null); return (
{ console.log("onSubmit", values); popToRoot(); }} /> } > ); } ``` {% endtab %} {% endtabs %} ## API Reference ### Form Shows a list of form items such as Form.TextField. Optionally add a Form.LinkAccessory in the right-hand side of the navigation bar. #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | actions | A reference to an ActionPanel. | 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 | | searchBarAccessory | Form.LinkAccessory, string>
| - | ### Form.TextField A form item with a text field for input. #### Example {% tabs %} {% tab title="Uncontrolled text field" %} ```typescript import { ActionPanel, Form, Action } from "@raycast/api"; export default function Command() { return (
console.log(values)} /> } > ); } ``` {% endtab %} {% tab title="Controlled text field" %} ```typescript import { ActionPanel, Form, Action } from "@raycast/api"; import { useState } from "react"; export default function Command() { const [name, setName] = useState(""); return (
console.log(values)} /> } > ); } ``` {% endtab %} {% endtabs %} #### Props | 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 | - | #### Methods (Imperative API) | Name | Signature | Description | | ----- | ----------------------- | -------------------------------------------------------------------------- | | focus | () => void | Makes the item request focus. | | reset | () => void | Resets the form item to its initial value, or `defaultValue` if specified. | ### Form.PasswordField A form item with a secure text field for password-entry in which the entered characters must be kept secret. #### Example {% tabs %} {% tab title="Uncontrolled password field" %} ```typescript import { ActionPanel, Form, Action } from "@raycast/api"; export default function Command() { return (
console.log(values)} /> } > ); } ``` {% endtab %} {% tab title="Controlled password field" %} ```typescript import { ActionPanel, Form, Action } from "@raycast/api"; import { useState } from "react"; export default function Command() { const [password, setPassword] = useState(""); return (
console.log(values)} /> } > ); } ``` {% endtab %} {% endtabs %} #### Props | 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 | - | #### Methods (Imperative API) | Name | Signature | Description | | ----- | ----------------------- | -------------------------------------------------------------------------- | | focus | () => void | Makes the item request focus. | | reset | () => void | Resets the form item to its initial value, or `defaultValue` if specified. | ### Form.TextArea A form item with a text area for input. The item supports multiline text entry. #### Example {% tabs %} {% tab title="Uncontrolled text area" %} ```typescript 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 (
console.log(values)} /> } > ); } ``` {% endtab %} {% tab title="Controlled text area" %} ```typescript import { ActionPanel, Form, Action } from "@raycast/api"; import { useState } from "react"; export default function Command() { const [description, setDescription] = useState(""); return (
console.log(values)} /> } > ); } ``` {% endtab %} {% endtabs %} #### Props | 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 | - | #### Methods (Imperative API) | Name | Signature | Description | | ----- | ----------------------- | -------------------------------------------------------------------------- | | focus | () => void | Makes the item request focus. | | reset | () => void | Resets the form item to its initial value, or `defaultValue` if specified. | ### Form.Checkbox A form item with a checkbox. #### Example {% tabs %} {% tab title="Uncontrolled checkbox" %} ```typescript import { ActionPanel, Form, Action } from "@raycast/api"; export default function Command() { return (
console.log(values)} /> } > ); } ``` {% endtab %} {% tab title="Controlled checkbox" %} ```typescript import { ActionPanel, Form, Action } from "@raycast/api"; import { useState } from "react"; export default function Command() { const [checked, setChecked] = useState(true); return (
console.log(values)} /> } > ); } ``` {% endtab %} {% endtabs %} #### Props | 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 | - | #### Methods (Imperative API) | Name | Signature | Description | | ----- | ----------------------- | -------------------------------------------------------------------------- | | focus | () => void | Makes the item request focus. | | reset | () => void | Resets the form item to its initial value, or `defaultValue` if specified. | ### Form.DatePicker A form item with a date picker. #### Example {% tabs %} {% tab title="Uncontrolled date picker" %} ```typescript import { ActionPanel, Form, Action } from "@raycast/api"; export default function Command() { return (
console.log(values)} /> } > ); } ``` {% endtab %} {% tab title="Controlled date picker" %} ```typescript import { ActionPanel, Form, Action } from "@raycast/api"; import { useState } from "react"; export default function Command() { const [date, setDate] = useState(null); return (
console.log(values)} /> } > ); } ``` {% endtab %} {% endtabs %} #### Props | 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. | Date | - | | 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 | - | | max | The maximum date (inclusive) allowed for selection. | Date | - | | min | The minimum date (inclusive) allowed for selection. | Date | - | | 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 | - | | type | Indicates what types of date components can be picked | Form.DatePicker.Type | - | | value | The current value of the item. | Date | - | | onBlur | The callback that will be triggered when the item loses its focus. | (event: FormEvent<Date \| null>) => void | - | | onChange | The callback which will be triggered when the `value` of the item changes. | (newValue: Date \| null) => void | - | | onFocus | The callback which will be triggered should be called when the item is focused. | (event: FormEvent<Date \| null>) => void | - | #### Methods (Imperative API) | Name | Signature | Description | | ----- | ----------------------- | -------------------------------------------------------------------------- | | focus | () => void | Makes the item request focus. | | reset | () => void | Resets the form item to its initial value, or `defaultValue` if specified. | #### Form.DatePicker.isFullDay A method that determines if a given date represents a full day or a specific time. ```ts import { ActionPanel, Form, Action } from "@raycast/api"; export default function Command() { return (
{ if (Form.DatePicker.isFullDay(values.reminderDate)) { // the event is for a full day } else { // the event is at a specific time } }} /> } > ); } ``` ### Form.Dropdown A form item with a dropdown menu. #### Example {% tabs %} {% tab title="Uncontrolled dropdown" %} ```typescript import { ActionPanel, Form, Action } from "@raycast/api"; export default function Command() { return (
console.log(values)} /> } > ); } ``` {% endtab %} {% tab title="Controlled dropdown" %} ```typescript import { ActionPanel, Form, Action } from "@raycast/api"; import { useState } from "react"; export default function Command() { const [programmingLanguage, setProgrammingLanguage] = useState("typescript"); return (
console.log(values)} /> } > ); } ``` {% endtab %} {% endtabs %} #### Props | 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 | - | | children | Sections or items. If Form.Dropdown.Item elements are specified, a default section is automatically created. | React.ReactNode | - | | 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 | - | | 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. | | 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 | - | | 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 item should be persisted after submitting, and restored next time the form 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` | | 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 | - | | onSearchTextChange | Callback triggered when the search bar text changes. | (text: string) => void | - | #### Methods (Imperative API) | Name | Signature | Description | | ----- | ----------------------- | -------------------------------------------------------------------------- | | focus | () => void | Makes the item request focus. | | reset | () => void | Resets the form item to its initial value, or `defaultValue` if specified. | ### Form.Dropdown.Item A dropdown item in a Form.Dropdown #### Example ```typescript import { Action, ActionPanel, Form, Icon } from "@raycast/api"; export default function Command() { return (
console.log(values)} /> } > ); } ``` #### Props | 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 | A optional icon displayed for the item. | Image.ImageLike | - | | 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 | ### Form.Dropdown.Section Visually separated group of dropdown items. Use sections to group related menu items together. #### Example ```typescript import { ActionPanel, Form, Action } from "@raycast/api"; export default function Command() { return (
console.log(values)} /> } > ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | children | The item elements of the section. | React.ReactNode | - | | title | Title displayed above the section | string | - | ### Form.TagPicker A form item with a tag picker that allows the user to select multiple items. #### Example {% tabs %} {% tab title="Uncontrolled tag picker" %} ```typescript import { ActionPanel, Form, Action } from "@raycast/api"; export default function Command() { return (
console.log(values)} /> } > ); } ``` {% endtab %} {% tab title="Controlled tag picker" %} ```typescript import { ActionPanel, Form, Action } from "@raycast/api"; import { useState } from "react"; export default function Command() { const [countries, setCountries] = useState(["ger", "ned", "pol"]); return (
console.log(values)} /> } > ); } ``` {% endtab %} {% endtabs %} #### Props | 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 | - | | children | The list of tags. | React.ReactNode | - | | 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 token 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 | - | #### Methods (Imperative API) | Name | Signature | Description | | ----- | ----------------------- | -------------------------------------------------------------------------- | | focus | () => void | Makes the item request focus. | | reset | () => void | Resets the form item to its initial value, or `defaultValue` if specified. | ### Form.TagPicker.Item A tag picker item in a Form.TagPicker. #### Example ```typescript import { ActionPanel, Color, Form, Icon, Action } from "@raycast/api"; export default function Command() { return (
console.log(values)} /> } > ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | title* | The display title of the tag. | string | - | | value* | Value of the tag. Make sure to assign unique value for each item. | string | - | | icon | An icon to show in the tag. | Image.ImageLike | - | ### Form.Separator A form item that shows a separator line. Use for grouping and visually separating form items. #### Example ```typescript import { ActionPanel, Form, Action } from "@raycast/api"; export default function Command() { return (
console.log(values)} /> } > ); } ``` ### Form.FilePicker A form item with a button to open a dialog to pick some files and/or some directories (depending on its props). {% hint style="info" %} While the user picked some items that existed, it might be possible for them to be deleted or changed when the `onSubmit` callback is called. Hence you should always make sure that the items exist before acting on them! {% endhint %} #### Example {% tabs %} {% tab title="Uncontrolled file picker" %} ```typescript import { ActionPanel, Form, Action } from "@raycast/api"; import fs from "fs"; export default function Command() { return (
{ const files = values.files.filter((file: any) => fs.existsSync(file) && fs.lstatSync(file).isFile()); console.log(files); }} /> } > ); } ``` {% endtab %} {% tab title="Single selection file picker" %} ```typescript import { ActionPanel, Form, Action } from "@raycast/api"; import fs from "fs"; export default function Command() { return (
{ const file = values.files[0]; if (!fs.existsSync(file) || !fs.lstatSync(file).isFile()) { return false; } console.log(file); }} /> } > ); } ``` {% endtab %} {% tab title="Directory picker" %} ```typescript import { ActionPanel, Form, Action } from "@raycast/api"; import fs from "fs"; export default function Command() { return (
{ const folder = values.folders[0]; if (!fs.existsSync(folder) || fs.lstatSync(folder).isDirectory()) { return false; } console.log(folder); }} /> } > ); } ``` {% endtab %} {% tab title="Controlled file picker" %} ```typescript import { ActionPanel, Form, Action } from "@raycast/api"; import { useState } from "react"; export default function Command() { const [files, setFiles] = useState([]); return (
console.log(values)} /> } > ); } ``` {% endtab %} {% endtabs %} #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | id* | ID of the form item. Make sure to assign each form item a unique id. | string | - | | allowMultipleSelection | Indicates whether the user can select multiple items or only one. | boolean | `true` | | autoFocus | Indicates whether the item should be focused automatically once the form is rendered. | boolean | - | | canChooseDirectories | Indicates whether it's possible to choose a directory. | boolean | `false` | | canChooseFiles | Indicates whether it's possible to choose a file. | boolean | `true` | | 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 | - | | showHiddenFiles | Indicates whether the file picker displays files that are normally hidden from the user. | boolean | `false` | | 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 | - | #### Methods (Imperative API) | Name | Signature | Description | | ----- | ----------------------- | -------------------------------------------------------------------------- | | focus | () => void | Makes the item request focus. | | reset | () => void | Resets the form item to its initial value, or `defaultValue` if specified. | ### Form.Description A form item with a simple text label. Do _not_ use this component to show validation messages for other form fields. #### Example ```typescript import { ActionPanel, Form, Action } from "@raycast/api"; export default function Command() { return (
console.log(values)} /> } > ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | text* | Text that will be displayed in the middle. | string | - | | title | The display title of the left side from the description item. | string | - | ### Form.LinkAccessory A link that will be shown in the right-hand side of the navigation bar. #### Example ```typescript import { ActionPanel, Form, Action } from "@raycast/api"; export default function Command() { return (
} actions={ console.log(values)} /> } > ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | target* | The target of the link. | string | - | | text* | The text value of the item. | string | - | ## Types #### Form.Event Some Form.Item callbacks (like `onFocus` and `onBlur`) can return a `Form.Event` object that you can use in a different ways. | Property | Description | Type | | :--- | :--- | :--- | | target* | An interface containing target data related to the event | { id: string; value?: any } | | type* | A type of event | Form.Event.Type | #### Example ```typescript import { Form } from "@raycast/api"; export default function Main() { return (
{[1, 2, 3, 4, 5, 6, 7].map((num) => ( ))} {[1, 2, 3, 4, 5, 6, 7].map((num) => ( ))} ); } function logEvent(event: Form.Event) { console.log(`Event '${event.type}' has happened for '${event.target.id}'. Current 'value': '${event.target.value}'`); } ``` #### Form.Event.Type The different types of `Form.Event`. Can be `"focus"` or `"blur"`. ### Form.Values Values of items in the form. For type-safe form values, you can define your own interface. Use the ID's of the form items as the property name. #### Example ```typescript import { Form, Action, ActionPanel } from "@raycast/api"; interface Values { todo: string; due?: Date; } export default function Command() { function handleSubmit(values: Values) { console.log(values); } return (
} > ); } ``` #### Properties | Name | Type | Required | Description | | ----------------- | ----- | -------- | ------------------------------- | | \[itemId: string] | `any` | Yes | The form value of a given item. | ### Form.DatePicker.Type The types of date components the user can pick with a `Form.DatePicker`. #### Enumeration members | Name | Description | | -------- | ---------------------------------------------------------------- | | DateTime | Hour and second can be picked in addition to year, month and day | | Date | Only year, month, and day can be picked | --- ## Imperative API You can use React's [useRef](https://reactjs.org/docs/hooks-reference.html#useref) hook to create variables which have access to imperative APIs (such as `.focus()` or `.reset()`) exposed by the native form items. ```typescript import { useRef } from "react"; import { ActionPanel, Form, Action } from "@raycast/api"; interface FormValues { nameField: string; bioTextArea: string; datePicker: string; } export default function Command() { const textFieldRef = useRef(null); const textAreaRef = useRef(null); const datePickerRef = useRef(null); const passwordFieldRef = useRef(null); const dropdownRef = useRef(null); const tagPickerRef = useRef(null); const firstCheckboxRef = useRef(null); const secondCheckboxRef = useRef(null); async function handleSubmit(values: FormValues) { console.log(values); datePickerRef.current?.focus(); dropdownRef.current?.reset(); } return (
textFieldRef.current?.focus()} /> textAreaRef.current?.focus()} /> datePickerRef.current?.focus()} /> passwordFieldRef.current?.focus()} /> dropdownRef.current?.focus()} /> tagPickerRef.current?.focus()} /> firstCheckboxRef.current?.focus()} /> secondCheckboxRef.current?.focus()} /> textFieldRef.current?.reset()} /> textAreaRef.current?.reset()} /> datePickerRef.current?.reset()} /> passwordFieldRef.current?.reset()} /> dropdownRef.current?.reset()} /> tagPickerRef.current?.reset()} /> firstCheckboxRef.current?.reset()} /> secondCheckboxRef.current?.reset()} /> } > { console.log(newValue); }} ref={dropdownRef} > { console.log(t); }} > {["one", "two", "three"].map((tag) => ( ))} { console.log("first checkbox onChange ", checked); }} /> { console.log("second checkbox onChange ", checked); }} /> ); } ``` # Grid The `Grid` component is provided as an alternative to the List component when the defining characteristic of an item is an image. {% hint style="info" %} Because its API tries to stick as closely to List should be as simple as: - making sure you're using at least version 1.36.0 of the `@raycast/api` package - updating your imports from `import { List } from '@raycast/api'` to `import { Grid } from '@raycast/api'`; - removing the `isShowingDetail` prop from the top-level `List` component, along with all List.Items' `detail` prop - renaming all List.Items' h`icon` prop to `content` - removing all List.Item does not _currently_ support accessories - finally, replacing all usages of `List` with `Grid`. {% endhint %} ## Search Bar The search bar allows users to interact quickly with grid items. By default, Grid.Items matched to the item's `title` or `keywords`. ### Custom filtering 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 `Grid`'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. ```typescript import { useEffect, useState } from "react"; import { Grid } from "@raycast/api"; const items = [ { content: "🙈", keywords: ["see-no-evil", "monkey"] }, { content: "🥳", keywords: ["partying", "face"] }, ]; export default function Command() { const [searchText, setSearchText] = useState(""); const [filteredList, filterList] = useState(items); useEffect(() => { filterList(items.filter((item) => item.keywords.some((keyword) => keyword.includes(searchText)))); }, [searchText]); return ( {filteredList.map((item) => ( ))} ); } ``` ### Programmatically updating the search bar 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. To do so, you can use the `searchText` prop. ```typescript import { useState } from "react"; import { Action, ActionPanel, Grid } from "@raycast/api"; const items = [ { content: "🙈", keywords: ["see-no-evil", "monkey"] }, { content: "🥳", keywords: ["partying", "face"] }, ]; export default function Command() { const [searchText, setSearchText] = useState(""); return ( {items.map((item) => ( setSearchText(item.content)} /> } /> ))} ); } ``` ### Dropdown Some extensions may benefit from giving users a second filtering dimension. A media file management extension may allow users to view only videos or only images, an image-searching extension may allow switching ssearch engines, etc. This is where the `searchBarAccessory` prop 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. ### Pagination {% hint style="info" %} Pagination requires version 1.69.0 or higher of the `@raycast/api` package. {% endhint %} `Grid`s have built-in support for pagination. To opt in to pagination, you need to pass it a `pagination` prop, which is an object providing 3 pieces of information: - `onLoadMore` - will be called by Raycast when the user reaches the end of the grid, either using the keyboard or the mouse. When it gets called, the extension is expected to perform an async operation which eventually can result in items being appended to the end of the grid. - `hasMore` - indicates to Raycast whether it _should_ call `onLoadMore` when the user reaches the end of the grid. - `pageSize` - indicates how many placeholder items Raycast should add to the end of the grid when it calls `onLoadMore`. Once `onLoadMore` finishes executing, the placeholder items will be replaced by the newly-added grid items. Note that extensions have access to a limited amount of memory. As your extension paginates, its memory usage will increase. Paginating extensively could lead to the extension eventually running out of memory and crashing. To protect against the extension crashing due to memory exhaustion, Raycast monitors the extension's memory usage and employs heuristics to determine whether it's safe to paginate further. If it's deemed unsafe to continue paginating, `onLoadMore` will not be triggered when the user scrolls to the bottom, regardless of the `hasMore` value. Additionally, during development, a warning will be printed in the terminal. For convenience, most of the hooks, and one "from scratch". {% tabs %} {% tab title="GridWithUsePromisePagination.tsx" %} ```typescript import { setTimeout } from "node:timers/promises"; import { useState } from "react"; import { Grid } from "@raycast/api"; import { usePromise } from "@raycast/utils"; export default function Command() { const [searchText, setSearchText] = useState(""); const { isLoading, data, pagination } = usePromise( (searchText: string) => async (options: { page: number }) => { await setTimeout(200); const newData = Array.from({ length: 25 }, (_v, index) => ({ index, page: options.page, text: searchText })); return { data: newData, hasMore: options.page < 10 }; }, [searchText] ); return ( {data?.map((item) => ( ))} ); } ``` {% endtab %} {% tab title="GridWithPagination.tsx" %} ```typescript import { setTimeout } from "node:timers/promises"; import { useCallback, useEffect, useRef, useState } from "react"; import { Grid } from "@raycast/api"; type State = { searchText: string; isLoading: boolean; hasMore: boolean; data: { index: number; page: number; text: string; }[]; nextPage: number; }; const pageSize = 20; export default function Command() { const [state, setState] = useState({ searchText: "", isLoading: true, hasMore: true, data: [], nextPage: 0 }); const cancelRef = useRef(null); const loadNextPage = useCallback(async (searchText: string, nextPage: number, signal?: AbortSignal) => { setState((previous) => ({ ...previous, isLoading: true })); await setTimeout(200); const newData = Array.from({ length: pageSize }, (_v, index) => ({ index, page: nextPage, text: searchText, })); if (signal?.aborted) { return; } setState((previous) => ({ ...previous, data: [...previous.data, ...newData], isLoading: false, hasMore: nextPage < 10, })); }, []); const onLoadMore = useCallback(() => { setState((previous) => ({ ...previous, nextPage: previous.nextPage + 1 })); }, []); const onSearchTextChange = useCallback( (searchText: string) => { if (searchText === state.searchText) return; setState((previous) => ({ ...previous, data: [], nextPage: 0, searchText, })); }, [state.searchText] ); useEffect(() => { cancelRef.current?.abort(); cancelRef.current = new AbortController(); loadNextPage(state.searchText, state.nextPage, cancelRef.current?.signal); return () => { cancelRef.current?.abort(); }; }, [loadNextPage, state.searchText, state.nextPage]); return ( {state.data.map((item) => ( ))} ); } ``` {% endtab %} {% endtabs %} {% hint style="warning" %} Pagination might not work properly if all grid items are rendered and visible at once, as `onLoadMore` won't be triggered. This typically happens when an API returns 10 results by default, all fitting within the Raycast window. To fix this, try displaying more items, like 20. {% endhint %} ## Examples {% tabs %} {% tab title="Grid.tsx" %} ```jsx import { Grid } from "@raycast/api"; export default function Command() { return ( ); } ``` {% endtab %} {% tab title="GridWithSections.tsx" %} ```typescript import { Grid } from "@raycast/api"; export default function Command() { return ( ); } ``` {% endtab %} {% tab title="GridWithActions.tsx" %} ```typescript import { ActionPanel, Action, Grid } from "@raycast/api"; export default function Command() { return ( } /> ); } ``` {% endtab %} {% tab title="GridWithEmptyView.tsx" %} ```typescript import { useEffect, useState } from "react"; import { Grid, Image } from "@raycast/api"; export default function CommandWithCustomEmptyView() { const [state, setState] = useState<{ searchText: string; items: { content: Image.ImageLike; title: string }[]; }>({ searchText: "", items: [] }); useEffect(() => { console.log("Running effect after state.searchText changed. Current value:", JSON.stringify(state.searchText)); // perform an API call that eventually populates `items`. }, [state.searchText]); return ( setState((previous) => ({ ...previous, searchText: newValue }))}> {state.searchText === "" && state.items.length === 0 ? ( ) : ( state.items.map((item, index) => ) )} ); } ``` {% endtab %} {% endtabs %} ## API Reference ### Grid Displays Grid.Sections. The grid uses built-in filtering by indexing the title & keywords of its items. #### Example ```typescript import { Grid } from "@raycast/api"; const items = [ { content: "🙈", keywords: ["see-no-evil", "monkey"] }, { content: "🥳", keywords: ["partying", "face"] }, ]; export default function Command() { return ( {items.map((item) => ( ))} ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | actions | A reference to an ActionPanel. It will only be shown when there aren't any children. | React.ReactNode | - | | aspectRatio | Aspect ratio for the Grid.Item elements. Defaults to 1. | "1" or "3/2" or "2/3" or "4/3" or "3/4" or "16/9" or "9/16" | - | | children | Grid sections or items. If Grid.Item elements are specified, a default section is automatically created. | React.ReactNode | - | | columns | Column count for the grid's sections. Minimum value is 1, maximum value is 8. | number | `5` | | 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. | | fit | Fit for the Grid.Item | - | | inset | Indicates how much space there should be between a Grid.Item | - | | 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 | | pagination | Configuration for pagination | { hasMore: boolean; pageSize: number; onLoadMore: () => void } | - | | searchBarAccessory | Grid.Dropdown, string> | - | | 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 grid changes. | (id: string) => void | - | ### Grid.Dropdown A dropdown menu that will be shown in the right-hand-side of the search bar. #### Example ```typescript import { Grid, Image } from "@raycast/api"; import { useState } from "react"; const types = [ { id: 1, name: "Smileys", value: "smileys" }, { id: 2, name: "Animals & Nature", value: "animals-and-nature" }, ]; const items: { [key: string]: { content: Image.ImageLike; keywords: string[] }[] } = { smileys: [{ content: "🥳", keywords: ["partying", "face"] }], "animals-and-nature": [{ content: "🙈", keywords: ["see-no-evil", "monkey"] }], }; export default function Command() { const [type, setType] = useState("smileys"); return ( setType(newValue)}> {types.map((type) => ( ))} } > {(items[type] || []).map((item) => ( ))} ); } ``` #### Props | 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 | - | ### Grid.Dropdown.Item A dropdown item in a Grid.Dropdown #### Example ```typescript import { Grid } from "@raycast/api"; export default function Command() { return ( } > ); } ``` #### Props | 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. | Image.ImageLike | - | | 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 | ### Grid.Dropdown.Section Visually separated group of dropdown items. Use sections to group related menu items together. #### Example ```typescript import { Grid } from "@raycast/api"; export default function Command() { return ( } > ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | children | The item elements of the section. | React.ReactNode | - | | title | Title displayed above the section | string | - | ### Grid.EmptyView 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 items e.g. when searching for an image, a gif etc. Raycast provides a default `EmptyView` that will be displayed if the Grid 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 `Grid.Item`s. Note that the `EmptyView` is _never_ displayed if the `Grid`'s `isLoading` property is true and the search bar is empty. #### Example ```typescript import { useEffect, useState } from "react"; import { Grid, Image } from "@raycast/api"; export default function CommandWithCustomEmptyView() { const [state, setState] = useState<{ searchText: string; items: { content: Image.ImageLike; title: string }[]; }>({ searchText: "", items: [] }); useEffect(() => { console.log("Running effect after state.searchText changed. Current value:", JSON.stringify(state.searchText)); // perform an API call that eventually populates `items`. }, [state.searchText]); return ( setState((previous) => ({ ...previous, searchText: newValue }))}> {state.searchText === "" && state.items.length === 0 ? ( ) : ( state.items.map((item, index) => ) )} ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | actions | A reference to an ActionPanel. | React.ReactNode | - | | description | An optional description for why the empty view is shown. | string | - | | icon | An icon displayed in the center of the EmptyView. | Image.ImageLike | - | | title | The main title displayed for the Empty View. | string | - | ### Grid.Item A item in the Grid. This is one of the foundational UI components of Raycast. A grid item represents a single entity. It can be an image, an emoji, a GIF etc. You most likely want to perform actions on this item, so make it clear to the user what this item is about. #### Example ```typescript import { Grid } from "@raycast/api"; export default function Command() { return ( ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | content* | An image or color, optionally with a tooltip, representing the content of the grid item. | Image.ImageLike } } | - | | accessory | An optional Grid.Item.Accessory | - | | actions | An ActionPanel that will be updated for the selected grid item. | React.ReactNode | - | | id | ID of the item. This string is passed to the `onSelectionChange` handler of the Grid 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 ith Action.ToggleQuickLook. | { name?: string; path: string } | - | | subtitle | An optional subtitle displayed below the title. | string | - | | title | An optional title displayed below the content. | string | - | ### Grid.Section A group of related Grid.Item. Sections are a great way to structure your grid. For example, you can group photos taken in the same place or in the same day. This way, the user can quickly access what is most relevant. Sections can specify their own `columns`, `fit`, `aspectRatio` and `inset` props, separate from what is defined on the main Grid component. #### Example {% tabs %} {% tab title="GridWithSection.tsx" %} ```typescript import { Grid } from "@raycast/api"; export default function Command() { return ( ); } ``` {% endtab %} {% tab title="GridWithStyledSection.tsx" %} ```typescript import { Grid, Color } from "@raycast/api"; export default function Command() { return ( {Object.entries(Color).map(([key, value]) => ( ))} ); } ``` {% endtab %} {% endtabs %} #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | aspectRatio | Aspect ratio for the Grid.Item elements. Defaults to 1. | "1" or "3/2" or "2/3" or "4/3" or "3/4" or "16/9" or "9/16" | - | | children | The Grid.Item elements of the section. | React.ReactNode | - | | columns | Column count for the section. Minimum value is 1, maximum value is 8. | number | `5` | | fit | Fit for the Grid.Item | - | | inset | Inset for the Grid.Item | - | | subtitle | An optional subtitle displayed next to the title of the section. | string | - | | title | Title displayed above the section. | string | - | ## Types ### Grid.Item.Accessory An interface describing an accessory view in a `Grid.Item`. ### Grid.Inset An enum representing the amount of space there should be between a Grid Item's content and its borders. The absolute value depends on the value of Grid's `columns` prop. #### Enumeration members | Name | Description | | ------ | ------------- | | Small | Small insets | | Medium | Medium insets | | Large | Large insets | ### Grid.ItemSize (deprecated) An enum representing the size of the Grid's child Grid.Items. #### Enumeration members | Name | Description | | ------ | --------------------- | | Small | Fits 8 items per row. | | Medium | Fits 5 items per row. | | Large | Fits 3 items per row. | ### Grid.Fit An enum representing how Grid.Item's content should be fit. #### Enumeration members | Name | Description | | ------- | ------------------------------------------------------------------------------------------------------------------------------- | | Contain | The content will be contained within the grid cell, with vertical/horizontal bars if its aspect ratio differs from the cell's. | | Fill | The content will be scaled proportionally so that it fill the entire cell; parts of the content could end up being cropped out. | # Icons & Images ## API Reference ### Icon List of built-in icons that can be used for actions or list items. #### Example ```typescript import { Icon, List } from "@raycast/api"; export default function Command() { return ( ); } ``` #### Enumeration members |


AddPerson

|


Airplane

|


AirplaneFilled

| | :---: | :---: | :---: | |


AirplaneLanding

|


AirplaneTakeoff

|


Airpods

| |


Alarm

|


AlarmRinging

|


AlignCentre

| |


AlignLeft

|


AlignRight

|


AmericanFootball

| |


Anchor

|


AppWindow

|


AppWindowGrid2x2

| |


AppWindowGrid3x3

|


AppWindowList

|


AppWindowSidebarLeft

| |


AppWindowSidebarRight

|


ArrowClockwise

|


ArrowCounterClockwise

| |


ArrowDown

|


ArrowDownCircle

|


ArrowDownCircleFilled

| |


ArrowLeft

|


ArrowLeftCircle

|


ArrowLeftCircleFilled

| |


ArrowNe

|


ArrowRight

|


ArrowRightCircle

| |


ArrowRightCircleFilled

|


ArrowUp

|


ArrowUpCircle

| |


ArrowUpCircleFilled

|


ArrowsContract

|


ArrowsExpand

| |


AtSymbol

|


BandAid

|


BankNote

| |


BarChart

|


BarCode

|


BathTub

| |


Battery

|


BatteryCharging

|


BatteryDisabled

| |


Bell

|


BellDisabled

|


Bike

| |


Binoculars

|


Bird

|


BlankDocument

| |


Bluetooth

|


Boat

|


Bold

| |


Bolt

|


BoltDisabled

|


Book

| |


Bookmark

|


Box

|


Brush

| |


Bubble

|


Bug

|


Building

| |


BulletPoints

|


BullsEye

|


BullsEyeMissed

| |


Buoy

|


Calculator

|


Calendar

| |


Camera

|


Car

|


Cart

| |


Cd

|


Center

|


Check

| |


CheckCircle

|


CheckList

|


CheckRosette

| |


Checkmark

|


ChessPiece

|


ChevronDown

| |


ChevronDownSmall

|


ChevronLeft

|


ChevronLeftSmall

| |


ChevronRight

|


ChevronRightSmall

|


ChevronUp

| |


ChevronUpDown

|


ChevronUpSmall

|


Circle

| |


CircleDisabled

|


CircleEllipsis

|


CircleFilled

| |


CircleProgress

|


CircleProgress100

|


CircleProgress25

| |


CircleProgress50

|


CircleProgress75

|


ClearFormatting

| |


Clipboard

|


Clock

|


Cloud

| |


CloudLightning

|


CloudRain

|


CloudSnow

| |


CloudSun

|


Code

|


CodeBlock

| |


Cog

|


Coin

|


Coins

| |


CommandSymbol

|


Compass

|


ComputerChip

| |


Contrast

|


CopyClipboard

|


CreditCard

| |


CricketBall

|


Crop

|


Crown

| |


Crypto

|


DeleteDocument

|


Desktop

| |


Devices

|


Dna

|


Document

| |


Dot

|


Download

|


Droplets

| |


Duplicate

|


EditShape

|


Eject

| |


Ellipsis

|


Emoji

|


EmojiSad

| |


Envelope

|


Eraser

|


ExclamationMark

| |


Exclamationmark

|


Exclamationmark2

|


Exclamationmark3

| |


Eye

|


EyeDisabled

|


EyeDropper

| |


Female

|


FilmStrip

|


Filter

| |


Finder

|


Fingerprint

|


Flag

| |


Folder

|


Footprints

|


Forward

| |


ForwardFilled

|


FountainTip

|


FullSignal

| |


GameController

|


Gauge

|


Gear

| |


Geopin

|


Germ

|


Gift

| |


Glasses

|


Globe

|


Goal

| |


Hammer

|


HardDrive

|


Hashtag

| |


Heading

|


Headphones

|


Heart

| |


HeartDisabled

|


Heartbeat

|


Highlight

| |


Hourglass

|


House

|


Humidity

| |


Image

|


Important

|


Info

| |


Italics

|


Key

|


Keyboard

| |


Layers

|


Leaderboard

|


Leaf

| |


LevelMeter

|


LightBulb

|


LightBulbOff

| |


LineChart

|


Link

|


List

| |


Livestream

|


LivestreamDisabled

|


Lock

| |


LockDisabled

|


LockUnlocked

|


Logout

| |


Lorry

|


Lowercase

|


MagnifyingGlass

| |


Male

|


Map

|


Mask

| |


Maximize

|


MedicalSupport

|


Megaphone

| |


MemoryChip

|


MemoryStick

|


Message

| |


Microphone

|


MicrophoneDisabled

|


Minimize

| |


Minus

|


MinusCircle

|


MinusCircleFilled

| |


Mobile

|


Monitor

|


Moon

| |


MoonDown

|


MoonUp

|


Moonrise

| |


Mountain

|


Mouse

|


Move

| |


Mug

|


MugSteam

|


Multiply

| |


Music

|


Network

|


NewDocument

| |


NewFolder

|


Paperclip

|


Paragraph

| |


Patch

|


Pause

|


PauseFilled

| |


Pencil

|


Person

|


PersonCircle

| |


PersonLines

|


Phone

|


PhoneRinging

| |


PieChart

|


Pill

|


Pin

| |


PinDisabled

|


Play

|


PlayFilled

| |


Plug

|


Plus

|


PlusCircle

| |


PlusCircleFilled

|


PlusMinusDivideMultiply

|


PlusSquare

| |


PlusTopRightSquare

|


Power

|


Print

| |


QuestionMark

|


QuestionMarkCircle

|


QuotationMarks

| |


QuoteBlock

|


Racket

|


Raindrop

| |


RaycastLogoNeg

|


RaycastLogoPos

|


Receipt

| |


Redo

|


RemovePerson

|


Repeat

| |


Replace

|


ReplaceOne

|


Reply

| |


Rewind

|


RewindFilled

|


Rocket

| |


Rosette

|


RotateAntiClockwise

|


RotateClockwise

| |


Rss

|


Ruler

|


SaveDocument

| |


Shield

|


ShortParagraph

|


Shuffle

| |


Sidebar

|


Signal0

|


Signal1

| |


Signal2

|


Signal3

|


Snippets

| |


Snowflake

|


SoccerBall

|


Speaker

| |


SpeakerDown

|


SpeakerHigh

|


SpeakerLow

| |


SpeakerOff

|


SpeakerOn

|


SpeakerUp

| |


SpeechBubble

|


SpeechBubbleActive

|


SpeechBubbleImportant

| |


SquareEllipsis

|


StackedBars1

|


StackedBars2

| |


StackedBars3

|


StackedBars4

|


Star

| |


StarCircle

|


StarDisabled

|


Stars

| |


Stop

|


StopFilled

|


Stopwatch

| |


Store

|


StrikeThrough

|


Sun

| |


Sunrise

|


Swatch

|


Switch

| |


Syringe

|


Tack

|


TackDisabled

| |


Tag

|


Temperature

|


TennisBall

| |


Terminal

|


Text

|


TextCursor

| |


TextInput

|


TextSelection

|


ThumbsDown

| |


ThumbsDownFilled

|


ThumbsUp

|


ThumbsUpFilled

| |


Ticket

|


Torch

|


Train

| |


Trash

|


Tray

|


Tree

| |


Trophy

|


TwoPeople

|


Umbrella

| |


Underline

|


Undo

|


Upload

| |


Uppercase

|


Video

|


VideoDisabled

| |


Wallet

|


Wand

|


Warning

| |


Waveform

|


Weights

|


Wifi

| |


WifiDisabled

|


Wind

|


Window

| |


Windsock

|


WrenchScrewdriver

|


WristWatch

| |


XMarkCircle

|


XMarkCircleFilled

|


XMarkCircleHalfDash

| |


XMarkTopRightSquare

|


Xmark

| ### Image.Mask Available masks that can be used to change the shape of an image. Can be handy to shape avatars or other items in a list. #### Example ```typescript import { Image, List } from "@raycast/api"; export default function Command() { return ( ); } ``` #### Enumeration members | Name | Value | | :--------------- | :----------------- | | Circle | "circle" | | RoundedRectangle | "roundedRectangle" | ## Types ### Image Display different types of images, including network images or bundled assets. Apply image transforms to the source, such as a `mask` or a `tintColor`. {% hint style="info" %} Tip: Suffix your local assets with `@dark` to automatically provide a dark theme option, eg: `icon.png` and `icon@dark.png`. {% endhint %} #### Example ```typescript // Built-in icon const icon = Icon.Eye; // Built-in icon with tint color const tintedIcon = { source: Icon.Bubble, tintColor: Color.Red }; // Bundled asset with circular mask const avatar = { source: "avatar.png", mask: Image.Mask.Circle }; // Implicit theme-aware icon // with 'icon.png' and 'icon@dark.png' in the `assets` folder const icon = "icon.png"; // Explicit theme-aware icon const icon = { source: { light: "https://example.com/icon-light.png", dark: "https://example.com/icon-dark.png" } }; ``` #### Properties | Property | Description | Type | | :--- | :--- | :--- | | source* | The Image.Source | | fallback | Image.Fallback | | mask | A Image.Mask | | tintColor | A Color.ColorLike | ### FileIcon An icon as it's used in the Finder. #### Example ```typescript import { List } from "@raycast/api"; export default function Command() { return ( ); } ``` #### Properties | Property | Description | Type | | :--- | :--- | :--- | | fileIcon* | The path to a file or folder to get its icon from. | string | ### Image.ImageLike ```typescript ImageLike: URL | Asset | Icon | FileIcon | Image; ``` Union type for the supported image types. #### Example ```typescript import { Icon, Image, List } from "@raycast/api"; export default function Command() { return ( ); } ``` ### Image.Source ```typescript Image.Source: URL | Asset | Icon | { light: URL | Asset; dark: URL | Asset } ``` The source of an Image or a single emoji. For consistency, it's best to use the built-in Icon in lists, the Action Panel, and other places. If a specific icon isn't built-in, you can reference custom ones from the `assets` folder of the extension by file name, e.g. `my-icon.png`. Alternatively, you can reference an absolute HTTPS URL that points to an image or use an emoji. You can also specify different remote or local assets for light and dark theme. #### Example ```typescript import { Icon, List } from "@raycast/api"; export default function Command() { return ( ); } ``` ### Image.Fallback ```typescript Image.Fallback: Asset | Icon | { light: Asset; dark: Asset } ``` A fallback Image, a single emoji, or a theme-aware asset. Any specified `mask` or `tintColor` will also apply to the fallback image. #### Example ```typescript import { List } from "@raycast/api"; export default function Command() { return ( ); } ``` ### Image.URL Image is a string representing a URL. #### Example ```typescript import { List } from "@raycast/api"; export default function Command() { return ( ); } ``` ### Image.Asset Image is a string representing an asset from the `assets/` folder #### Example ```typescript import { List } from "@raycast/api"; export default function Command() { return ( ); } ``` --- description: >- The de-facto user interface in Raycast. Ideal to present similar data such as to-dos or files. --- # List 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. ## Search Bar The search bar allows users to interact quickly with list items. By default, List.Items matched to the item's `title` or `keywords`. ### Custom filtering 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. ```typescript 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 ( {filteredList.map((item) => ( console.log(`${item} selected`)} /> } /> ))} ); } ``` ### Programmatically updating the search bar 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. To do so, you can use the `searchText` prop. ```typescript 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 ( {items.map((item) => ( setSearchText(item)} /> } /> ))} ); } ``` ### Dropdown 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 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. ### Pagination {% hint style="info" %} Pagination requires version 1.69.0 or higher of the `@raycast/api` package. {% endhint %} `List`s have built-in support for pagination. To opt in to pagination, you need to pass it a `pagination` prop, which is an object providing 3 pieces of information: - `onLoadMore` - will be called by Raycast when the user reaches the end of the list, either using the keyboard or the mouse. When it gets called, the extension is expected to perform an async operation which eventually can result in items being appended to the end of the list. - `hasMore` - indicates to Raycast whether it _should_ call `onLoadMore` when the user reaches the end of the list. - `pageSize` - indicates how many placeholder items Raycast should add to the end of the list when it calls `onLoadMore`. Once `onLoadMore` finishes executing, the placeholder items will be replaced by the newly-added list items. Note that extensions have access to a limited amount of memory. As your extension paginates, its memory usage will increase. Paginating extensively could lead to the extension eventually running out of memory and crashing. To protect against the extension crashing due to memory exhaustion, Raycast monitors the extension's memory usage and employs heuristics to determine whether it's safe to paginate further. If it's deemed unsafe to continue paginating, `onLoadMore` will not be triggered when the user scrolls to the bottom, regardless of the `hasMore` value. Additionally, during development, a warning will be printed in the terminal. For convenience, most of the hooks, and one "from scratch". {% tabs %} {% tab title="ListWithUsePromisePagination.tsx" %} ```typescript import { setTimeout } from "node:timers/promises"; import { useState } from "react"; import { List } from "@raycast/api"; import { usePromise } from "@raycast/utils"; export default function Command() { const [searchText, setSearchText] = useState(""); const { isLoading, data, pagination } = usePromise( (searchText: string) => async (options: { page: number }) => { await setTimeout(200); const newData = Array.from({ length: 25 }, (_v, index) => ({ index, page: options.page, text: searchText, })); return { data: newData, hasMore: options.page < 10 }; }, [searchText] ); return ( {data?.map((item) => ( ))} ); } ``` {% endtab %} {% tab title="ListWithPagination.tsx" %} ```typescript import { setTimeout } from "node:timers/promises"; import { useCallback, useEffect, useRef, useState } from "react"; import { List } from "@raycast/api"; type State = { searchText: string; isLoading: boolean; hasMore: boolean; data: { index: number; page: number; text: string; }[]; nextPage: number; }; const pageSize = 20; export default function Command() { const [state, setState] = useState({ searchText: "", isLoading: true, hasMore: true, data: [], nextPage: 0 }); const cancelRef = useRef(null); const loadNextPage = useCallback(async (searchText: string, nextPage: number, signal?: AbortSignal) => { setState((previous) => ({ ...previous, isLoading: true })); await setTimeout(500); const newData = Array.from({ length: pageSize }, (_v, index) => ({ index, page: nextPage, text: searchText, })); if (signal?.aborted) { return; } setState((previous) => ({ ...previous, data: [...previous.data, ...newData], isLoading: false, hasMore: nextPage < 10, })); }, []); const onLoadMore = useCallback(() => { setState((previous) => ({ ...previous, nextPage: previous.nextPage + 1 })); }, []); const onSearchTextChange = useCallback( (searchText: string) => { if (searchText === state.searchText) return; setState((previous) => ({ ...previous, data: [], nextPage: 0, searchText, })); }, [state.searchText] ); useEffect(() => { cancelRef.current?.abort(); cancelRef.current = new AbortController(); loadNextPage(state.searchText, state.nextPage, cancelRef.current?.signal); return () => { cancelRef.current?.abort(); }; }, [loadNextPage, state.searchText, state.nextPage]); return ( {state.data.map((item) => ( ))} ); } ``` {% endtab %} {% endtabs %} {% hint style="warning" %} Pagination might not work properly if all list items are rendered and visible at once, as `onLoadMore` won't be triggered. This typically happens when an API returns 10 results by default, all fitting within the Raycast window. To fix this, try displaying more items, like 20. {% endhint %} ## Examples {% tabs %} {% tab title="List.tsx" %} ```jsx import { List } from "@raycast/api"; export default function Command() { return ( ); } ``` {% endtab %} {% tab title="ListWithSections.tsx" %} ```jsx import { List } from "@raycast/api"; export default function Command() { return ( ); } ``` {% endtab %} {% tab title="ListWithActions.tsx" %} ```jsx import { ActionPanel, Action, List } from "@raycast/api"; export default function Command() { return ( } /> ); } ``` {% endtab %} {% tab title="ListWithDetail.tsx" %} ```jsx 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((resolve) => resolve(pokemons))); return ( {data && data.map((pokemon) => { const props: Partial = showingDetail ? { detail: ( ), } : { accessories: [{ text: pokemon.types.join(" ") }] }; return ( setShowingDetail(!showingDetail)} /> } /> ); })} ); } ``` {% endtab %} {% tab title="ListWithEmptyView.tsx" %} ```typescript 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 ( setState((previous) => ({ ...previous, searchText: newValue }))}> {state.searchText === "" && state.items.length === 0 ? ( ) : ( state.items.map((item) => ) )} ); } ``` {% endtab %} {% endtabs %} ## API Reference ### List Displays List.Section. The list uses built-in filtering by indexing the title of list items and additionally keywords. #### Example ```typescript import { List } from "@raycast/api"; export default function Command() { return ( ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | actions | A reference to an ActionPanel. It will only be shown when there aren't any children. | 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 | | pagination | Configuration for pagination | { hasMore: boolean; pageSize: number; onLoadMore: () => void } | - | | searchBarAccessory | List.Dropdown, string> | - | | 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 | - | ### List.Dropdown A dropdown menu that will be shown in the right-hand-side of the search bar. #### Example ```typescript 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 ( { onDrinkTypeChange(newValue); }} > {drinkTypes.map((drinkType) => ( ))} ); } export default function Command() { const drinkTypes: DrinkType[] = [ { id: "1", name: "Beer" }, { id: "2", name: "Wine" }, ]; const onDrinkTypeChange = (newValue: string) => { console.log(newValue); }; return ( } > ); } ``` #### Props | 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 | - | ### List.Dropdown.Item A dropdown item in a List.Dropdown #### Example ```typescript import { List } from "@raycast/api"; export default function Command() { return ( } > ); } ``` #### Props | 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. | Image.ImageLike | - | | 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 | ### List.Dropdown.Section Visually separated group of dropdown items. Use sections to group related menu items together. #### Example ```typescript import { List } from "@raycast/api"; export default function Command() { return ( } > ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | children | The item elements of the section. | React.ReactNode | - | | title | Title displayed above the section | string | - | ### List.EmptyView 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. #### Example ```typescript 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 ( setState((previous) => ({ ...previous, searchText: newValue }))}> {state.searchText === "" && state.items.length === 0 ? ( ) : ( state.items.map((item) => ) )} ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | actions | A reference to an ActionPanel. | React.ReactNode | - | | description | An optional description for why the empty view is shown. | string | - | | icon | An icon displayed in the center of the EmptyView. | Image.ImageLike | - | | title | The main title displayed for the Empty View. | string | - | ### List.Item A item in the List. 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. #### Example ```typescript import { Icon, List } from "@raycast/api"; export default function Command() { return ( ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | title* | The main title displayed for that item, optionally with a tooltip. | string or { tooltip?: string; value: string } | - | | accessories | An optional array of List.Item.Accessory[] | - | | actions | An ActionPanel that will be updated for the selected list item. | 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. | Image.ImageLike } | - | | 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 } | - | ### List.Item.Detail 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. #### Example ```typescript import { List } from "@raycast/api"; export default function Command() { return ( } /> ); } ``` #### Props | 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 | - | ### List.Item.Detail.Metadata 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`. #### Example {% tabs %} {% tab title="Metadata + Markdown" %} ```typescript import { List } from "@raycast/api"; export default function Metadata() { const markdown = ` ![Illustration](https://assets.pokemon.com/assets/cms2/img/pokedex/full/001.png) There is a plant seed on its back right from the day this Pokémon is born. The seed slowly grows larger. `; return ( } /> } /> ); } ``` {% endtab %} {% tab title="Metadata Standalone" %} ```typescript import { List } from "@raycast/api"; export default function Metadata() { return ( } /> } /> ); } ``` {% endtab %} {% endtabs %} #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | children* | The elements of the Metadata view. | React.ReactNode | - | ### List.Item.Detail.Metadata.Label A title with, optionally, an icon and/or text to its right. #### Example ```typescript import { List } from "@raycast/api"; export default function Metadata() { return ( } /> } /> ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | title* | The title of the item. | string | - | | icon | An icon to illustrate the value of the item. | Image.ImageLike | - | | text | The text value of the item. Specifying `color` will display the text in the provided color. Defaults to Color.SecondaryText; value: string } | - | ### List.Item.Detail.Metadata.Link An item to display a link. #### Example ```typescript import { List } from "@raycast/api"; export default function Metadata() { return ( } /> } /> ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | target* | The target of the link. | string | - | | text* | The text value of the item. | string | - | | title* | The title shown above the item. | string | - | ### List.Item.Detail.Metadata.TagList A list of `Tags` displayed in a row. #### Example ```typescript import { List } from "@raycast/api"; export default function Metadata() { return ( } /> } /> ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | children* | The tags contained in the TagList. | React.ReactNode | - | | title* | The title shown above the item. | string | - | ### List.Item.Detail.Metadata.TagList.Item A Tag in a `List.Item.Detail.Metadata.TagList`. #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | color | Changes the text color to the provided color and sets a transparent background with the same color. | Color.ColorLike | - | | icon | The optional icon tag icon. Required if the tag has no text. | Image.ImageLike | - | | text | The optional tag text. Required if the tag has no icon. | string | - | | onAction | Callback that is triggered when the item is clicked. | () => void | - | ### List.Item.Detail.Metadata.Separator A metadata item that shows a separator line. Use it for grouping and visually separating metadata items. #### Example ```typescript import { List } from "@raycast/api"; export default function Metadata() { return ( } /> } /> ); } ``` ### List.Section A group of related List.Item. Sections are a great way to structure your list. For example, group GitHub issues with the same status and order them by priority. This way, the user can quickly access what is most relevant. #### Example ```typescript import { List } from "@raycast/api"; export default function Command() { return ( ); } ``` #### Props | Prop | Description | Type | Default | | :--- | :--- | :--- | :--- | | children | The List.Item elements of the section. | React.ReactNode | - | | subtitle | An optional subtitle displayed next to the title of the section. | string | - | | title | Title displayed above the section. | string | - | ## Types ### List.Item.Accessory An interface describing an accessory view in a `List.Item`. #### Properties | Property | Description | Type | | :--- | :--- | :--- | | tag* | A string or Date that will be used as the label, optionally colored. The date is formatted relatively to the current time (for example `new Date()` will be displayed as `"now"`, yesterday's Date will be displayed as "1d", etc.). Color changes the text color to the provided color and sets a transparent background with the same color. Defaults to Color.SecondaryText; value: string or Date or undefined or null } | | text | An optional text that will be used as the label, optionally colored. Color changes the text color to the provided color. Defaults to Color.SecondaryText; value: string or undefined or null } | | date | An optional Date that will be used as the label, optionally colored. The date is formatted relatively to the current time (for example `new Date()` will be displayed as `"now"`, yesterday's Date will be displayed as "1d", etc.). Color changes the text color to the provided color. Defaults to Color.SecondaryText; value: Date or undefined or null } | | icon | An optional Image.ImageLike or null | | tooltip | An optional tooltip shown when the accessory is hovered. | string or null | #### Example ```typescript import { Color, Icon, List } from "@raycast/api"; export default function Command() { return ( ); } ``` # Navigation ## API Reference ### useNavigation A hook that lets you push and pop view components in the navigation stack. You most likely won't use this hook too often. To push a new component, use the Push Action. When a user presses `ESC`, we automatically pop to the previous component. #### Signature ```typescript function useNavigation(): Navigation; ``` #### Example ```typescript import { Action, ActionPanel, Detail, useNavigation } from "@raycast/api"; function Ping() { const { push } = useNavigation(); return ( push()} /> } /> ); } function Pong() { const { pop } = useNavigation(); return ( } /> ); } export default function Command() { return ; } ``` #### Return A Navigation functions. Use the functions to alter the navigation stack. ## Types ### Navigation Return type of the useNavigation hook to perform push and pop actions. #### Properties | Property | Description | Type | | :--- | :--- | :--- | | pop* | Pop current view component from the navigation stack. | () => void | | push* | Push a new view component to the navigation stack. | (component: React.ReactNode, onPop: () => void) => void | # System Utilities This set of utilities exposes some of Raycast's native functionality to allow deep integration into the user's setup. For example, you can use the Application APIs to check if a desktop application is installed and then provide an action to deep-link into it. ## API Reference ### getApplications Returns all applications that can open the file or URL. #### Signature ```typescript async function getApplications(path?: PathLike): Promise; ``` #### Example {% tabs %} {% tab title="Find Application" %} ```typescript import { getApplications, Application } from "@raycast/api"; // it is a lot more reliable to get an app by its bundle ID than its path async function findApplication(bundleId: string): Application | undefined { const installedApplications = await getApplications(); return installedApplications.filter((application) => application.bundleId == bundleId); } ``` {% endtab %} {% tab title="List Installed Applications" %} ```typescript import { getApplications } from "@raycast/api"; export default async function Command() { const installedApplications = await getApplications(); console.log("The following applications are installed on your Mac:"); console.log(installedApplications.map((a) => a.name).join(", ")); } ``` {% endtab %} {% endtabs %} #### Parameters | Name | Description | Type | | :--- | :--- | :--- | | path | The path of the file or folder to get the applications for. If no path is specified, all installed applications are returned. | PathLike | #### Return An array of Application. ### getDefaultApplication Returns the default application that the file or URL would be opened with. #### Signature ```typescript async function getDefaultApplication(path: PathLike): Promise; ``` #### Example ```typescript import { getDefaultApplication } from "@raycast/api"; export default async function Command() { const defaultApplication = await getDefaultApplication(__filename); console.log(`Default application for JavaScript is: ${defaultApplication.name}`); } ``` #### Parameters | Name | Description | Type | | :--- | :--- | :--- | | path* | The path of the file or folder to get the default application for. | PathLike | #### Return A Promise that resolves with the default Application that would open the file or URL. If no application was found, the promise will be rejected. ### getFrontmostApplication Returns the frontmost application. #### Signature ```typescript async function getFrontmostApplication(): Promise; ``` #### Example ```typescript import { getFrontmostApplication } from "@raycast/api"; export default async function Command() => { const frontmostApplication = await getFrontmostApplication(); console.log(`The frontmost application is: ${frontmostApplication.name}`); }; ``` #### Return A Promise that resolves with the frontmost Application. If no application was found, the promise will be rejected. ### showInFinder Shows a file or directory in the Finder. #### Signature ```typescript async function showInFinder(path: PathLike): Promise; ``` #### Example ```typescript import { showInFinder } from "@raycast/api"; import { homedir } from "os"; import { join } from "path"; export default async function Command() { await showInFinder(join(homedir(), "Downloads")); } ``` #### Parameters | Name | Description | Type | | :--- | :--- | :--- | | path* | The path to show in the Finder. | PathLike | #### Return A Promise that resolves when the item is revealed in the Finder. ### trash Moves a file or directory to the Trash. #### Signature ```typescript async function trash(path: PathLike | PathLike[]): Promise; ``` #### Example ```typescript import { trash } from "@raycast/api"; import { writeFile } from "fs/promises"; import { homedir } from "os"; import { join } from "path"; export default async function Command() { const file = join(homedir(), "Desktop", "yolo.txt"); await writeFile(file, "I will be deleted soon!"); await trash(file); } ``` #### Parameters | Name | Description | Type | | :--- | :--- | :--- | | path* | | PathLike[] | #### Return A Promise that resolves when all files are moved to the trash. ### open Opens a target with the default application or specified application. #### Signature ```typescript async function open(target: string, application?: Application | string): Promise; ``` #### Example ```typescript import { open } from "@raycast/api"; export default async function Command() { await open("https://www.raycast.com", "com.google.Chrome"); } ``` #### Parameters | Name | Description | Type | | :--- | :--- | :--- | | target* | The file, folder or URL to open. | string | | application | The application name to use for opening the file. If no application is specified, the default application as determined by the system is used to open the specified file. Note that you can use the application name, app identifier, or absolute path to the app. | string or Application | #### Return A Promise that resolves when the target has been opened. ### captureException Report the provided exception to the Developer Hub. This helps in handling failures gracefully while staying informed about the occurrence of the failure. #### Signature ```typescript function captureException(exception: unknown): void; ``` #### Example ```typescript import { open, captureException, showToast, Toast } from "@raycast/api"; export default async function Command() { const url = "https://www.raycast.com"; const app = "Google Chrome"; try { await open(url, app); } catch (e: unknown) { captureException(e); await showToast({ style: Toast.Style.Failure, title: `Could not open ${url} in ${app}.`, }); } } ``` #### Parameters | Name | Description | Type | | :--- | :--- | :--- | | target* | The file, folder or URL to open. | string | | application | The application name to use for opening the file. If no application is specified, the default application as determined by the system is used to open the specified file. Note that you can use the application name, app identifier, or absolute path to the app. | string or Application | ## Types ### Application An object that represents a locally installed application on the system. It can be used to open files or folders in a specific application. Use getApplications or getDefaultApplication to get applications that can open a specific file or folder. #### Properties | Property | Description | Type | | :--- | :--- | :--- | | name* | The display name of the application. | string | | path* | The absolute path to the application bundle, e.g. `/Applications/Raycast.app`, | string | | bundleId | The bundle identifier of the application, e.g. `com.raycast.macos`. | string | | localizedName | The localized name of the application. | string | ### PathLike ```typescript PathLike: string | Buffer | URL; ``` Supported path types. # Raycast Window & Search Bar ## API Reference ### clearSearchBar Clear the text in the search bar. #### Signature ```typescript async function clearSearchBar(options?: { forceScrollToTop?: boolean }): Promise; ``` #### Parameters | Name | Description | Type | | :--- | :--- | :--- | | options | Can be used to control the behaviour after the search bar is cleared. | Object | | options.forceScrollToTop | Can be used to force scrolling to the top. Defaults to scrolling to the top after the the search bar was cleared. | boolean | #### Return A Promise that resolves when the search bar is cleared. ### closeMainWindow Closes the main Raycast window. #### Signature ```typescript async function closeMainWindow(options?: { clearRootSearch?: boolean; popToRootType?: PopToRootType }): Promise; ``` #### Example ```typescript import { closeMainWindow } from "@raycast/api"; import { setTimeout } from "timers/promises"; export default async function Command() { await setTimeout(1000); await closeMainWindow({ clearRootSearch: true }); } ``` You can use the `popToRootType` parameter to temporarily prevent Raycast from applying the user's "Pop to Root Search" preference in Raycast; for example, when you need to interact with an external system utility and then allow the user to return back to the view command: ```typescript import { closeMainWindow, PopToRootType } from "@raycast/api"; export default async () => { await closeMainWindow({ popToRootType: PopToRootType.Suspended }); }; ``` #### Parameters | Name | Description | Type | | :--- | :--- | :--- | | options | Can be used to control the behaviour after closing the main window. | Object | | options.clearRootSearch | Clears the text in the root search bar and scrolls to the top | boolean | | options.popToRootType | Defines the pop to root behavior (PopToRootType | #### Return A Promise that resolves when the main window is closed. ### popToRoot Pops the navigation stack back to root search. #### Signature ```typescript async function popToRoot(options?: { clearSearchBar?: boolean }): Promise; ``` #### Example ```typescript import { Detail, popToRoot } from "@raycast/api"; import { useEffect } from "react"; import { setTimeout } from "timers"; export default function Command() { useEffect(() => { setTimeout(() => { popToRoot({ clearSearchBar: true }); }, 3000); }, []); return ; } ``` #### Parameters | Name | Description | Type | | :--- | :--- | :--- | | options | Can be used to control the behaviour after going back to the root search. | Object | | options.clearSearchBar | | boolean | #### Return A Promise that resolves when Raycast popped to root. ## Types ### PopToRootType Defines the pop to root behavior when the main window is closed. #### Enumeration members | Name | Description | | :-------- | :------------------------------------------------------------- | | Default | Respects the user's "Pop to Root Search" preference in Raycast | | Immediate | Immediately pops back to root | | Suspended | Prevents Raycast from popping back to root | # Window Management The Window Management API provides developers with some functions to create commands with some advanced logic to move Windows around. {% hint style="info" %} Some users might not have access to this API. If a user doesn't have access to Raycast Pro, they will be asked if they want to get access when your extension calls the Window Management API. If the user doesn't wish to get access, the API call will throw an error. You can check if a user has access to the API using `environment.canAccess(WindowManagement)`. {% endhint %} ## API Reference ### WindowManagement.getActiveWindow Gets the active Window. #### Signature ```typescript async function getActiveWindow(): Promise; ``` #### Example ```typescript import { WindowManagement, showToast } from "@raycast/api"; export default async function Command() { try { const window = await WindowManagement.getActiveWindow(); if (window.positionable) { WindowManagement.setWindowBounds({ id: window.id, bounds: { position: { x: 100 } } }); } } catch (error) { showToast({ title: "Could not move window", message: error.message, style: Toast.Style.Failure }); } } ``` #### Return A Promise that resolves with the active Window. If no window is active, the promise will be rejected. ### WindowManagement.getWindowsOnActiveDesktop Gets the list of Window. #### Signature ```typescript async function getWindowsOnActiveDesktop(): Promise; ``` #### Example ```typescript import { WindowManagement, showToast } from "@raycast/api"; export default async function Command() { const windows = await WindowManagement.getWindowsOnActiveDesktop(); const chrome = windows.find((x) => x.application?.bundleId === "com.google.Chrome"); if (!chrome) { showToast({ title: "Couldn't find chrome", style: Toast.Style.Failure }); return; } WindowManagement.setWindowBounds({ id: chrome.id, bounds: { position: { x: 100 } } }); } ``` #### Return A Promise that resolves with an array of Windows. ### WindowManagement.getDesktops Gets the list of Desktops available across all screens. #### Signature ```typescript async function getDesktops(): Promise; ``` #### Example ```typescript import { WindowManagement, showToast } from "@raycast/api"; export default function Command() { const desktops = await WindowManagement.getDesktops(); const screens = Set(desktops.map((desktop) => desktop.screenId)); showToast({ title: `Found ${desktops.length} desktops on ${screens.size} screens.` }); } ``` #### Return A Promise that resolves with the desktops. ### WindowManagement.setWindowBounds Move a Window or make it fullscreen. #### Signature ```typescript async function setWindowBounds( options: { id: string } & ( | { bounds: { position?: { x?: number; y?: number }; size?: { width?: number; height?: number }; }; desktopId?: string; } | { bounds: "fullscreen"; } ) ): Promise; ``` #### Example ```typescript import { WindowManagement, showToast } from "@raycast/api"; export default async function Command() { try { const window = await WindowManagement.getActiveWindow(); if (window.positionable) { WindowManagement.setWindowBounds({ id: window.id, bounds: { position: { x: 100 } } }); } } catch (error) { showToast({ title: "Could not move window", message: error.message, style: Toast.Style.Failure }); } } ``` #### Parameters | Name | Description | Type | | :--- | :--- | :--- | | options* | | { id: string } or { bounds: { position?: { x?: number; y?: number }; size?: { height?: number; width?: number } }; desktopId?: string } or { id: string } or { bounds: "fullscreen" } | #### Return A Promise that resolves with the window was moved. If the move isn't possible (for example trying to make a window fullscreen that doesn't support it), the promise will be rejected. ## Types ### WindowManagement.Window A Window from an Application. #### Properties | Property | Description | Type | | :--- | :--- | :--- | | active* | | boolean | | bounds* | | { position: { x: number; y: number }; size: { height: number; width: number } } or "fullscreen" | | desktopId* | | string | | fullScreenSettable* | | boolean | | id* | | string | | positionable* | | boolean | | resizable* | | boolean | | application | | Application | ### WindowManagement.Desktop A Desktop represents a virtual desktop on a Screen. #### Properties | Property | Description | Type | | :--- | :--- | :--- | | active* | | boolean | | id* | | string | | screenId* | | string | | size* | | { height: number; width: number } | | type* | | WindowManagement.DesktopType | ### WindowManagement.DesktopType The type of a Desktop. #### Enumeration members | Name | Description | | :--------- | :---------------------------------------------------------------------------------------- | | User | The default Desktop type. It can contain any number of Window | | FullScreen | A Desktop made of a single fullscreen window |