> ## Documentation Index > Fetch the complete documentation index at: https://www.canva.dev/docs/apps/llms.txt > Use this file to discover all available pages before exploring further. # Using color selectors How to prompt users to select a color. Sometimes, apps want to prompt users to select a color. For example, an app for creating patterns might want to prompt users to select the colors for a pattern. To ensure a consistent user experience, apps can use the Canva Developers SDK to open a built-in color selector flyout and detect the selection of colors. ## Features * A familiar user experience that's deeply integrated with Canva. * Integrated with [Brand Kit](https://www.canva.com/help/brand-kit/), helping teams to remain on-brand. * [Canva Pro](https://www.canva.com/pro/) users automatically get access to Pro-only features. The color selector feature works within different [Canva design types](https://www.canva.dev/docs/apps/designs/), such as Presentations and Docs. See [Feature support](https://www.canva.dev/docs/apps/feature-support/) for more information. ## The user experience Apps are responsible for determining how a color selector opens, but a common pattern is to open the selector when a user clicks a `Swatch` component. The color selector itself appears in a flyout interface that's "pinned" to the element that opened it. The exact position of the flyout is calculated and controlled by Canva. Users can select document colors, Brand Kit colors, or default colors. If non-breaking features are added to the color selector in the future, they will be automatically available to apps without requiring code changes. While the color selector is open, an invisible overlay is rendered on top of the app. This overlay blocks interactions with the app, such as clicking or scrolling, until the color selector is closed. ## Color selection scopes The color selector can be configured with one or more *scopes*. These scopes determine the user experience. At the moment, `"solid"` is the only supported scope. When enabled, this scope allows the user to select solid colors. An example of a scope that will be supported in the future is the `"palette"` scope. This scope will allow users to select color palettes — that is, combinations of colors. ## How to open a color selector ### Step 1: Enable the required permissions In the Developer Portal, enable the following permissions: * `canva:brandkit:read` * `canva:design:content:read` In the future, the Developers SDK will throw an error if the required permissions aren't enabled. To learn more, see [Permissions](https://www.canva.dev/docs/apps/configuring-intents-permissions/). ### Step 2: Set up an anchor An *anchor* is the element to which the color selector will be "pinned" when it's open. This could be a custom component, but we generally recommend using an [App UI Kit](https://www.canva.dev/docs/apps/app-ui-kit/) component, such as the `Swatch` component: ```tsx import { Rows, Swatch } from "@canva/app-ui-kit"; import * as React from "react"; import * as styles from "styles/components.css"; export function App() { return (
{ // code goes here }} />
); } ``` ### Step 3: Open the color selector 1. Import the `openColorSelector` method from the `@canva/asset` package: ```tsx import { openColorSelector } from "@canva/asset"; ``` 2. In the `onClick` handler, get the position and dimensions of the anchor: ```tsx { const anchor = event.currentTarget.getBoundingClientRect(); }} /> ``` 3. Register a callback with the `openColorSelector` method, passing in the position and dimensions of the anchor as the first argument, and setting the scope and callback as the second argument: ```tsx { const anchor = event.currentTarget.getBoundingClientRect(); await openColorSelector(anchor, { scopes: ["solid"], onColorSelect: (event) => { console.log(event.selection); }, }); }} /> ``` The callback receives an object as its only argument. This object contains information about the color selection event. ### Step 4: Handle the color selection 1. Set up a state variable for tracking the currently selected color: ```tsx const [color, setColor] = React.useState("#ff0099"); ``` 2. Pass the color state into the `Swatch` component and, in the `onClick` handler, update the state variable: ```tsx { const anchor = event.currentTarget.getBoundingClientRect(); await openColorSelector(anchor, { scopes: ["solid"], onColorSelect: (event) => { if (event.selection.type === "solid") { setColor(event.selection.hexString); } }, }); }} /> ``` ### (Optional) Step 5: Handle multiple colors Sometimes, apps need to render multiple selectable colors, such as by rendering multiple `Swatch` components. The problem is, when a user opens a color selector, the color that's displayed as selected defaults to the most recently selected color, even if the most recent color was selected via a different selector. This leads to the following bug: 1. In Color Selector #1, the user selects a color. 2. In Color Selector #2, the color from Color Selector #1 is display as selected. To solve this problem, explicitly define the color to display as selected for each color selector: ```tsx { const anchor = event.currentTarget.getBoundingClientRect(); await openColorSelector(anchor, { scopes: ["solid"], selectedColor: color ? { type: "solid", hexString: color, } : undefined, onColorSelect: (event) => { console.log(event.selection); }, }); }} /> ``` Here, we're passing the previously selected color into the `openColorSelector` method via the `selectedColor` property, or a value of `undefined` if there isn't a previously selected color. The `selectedColor` property is not required if an app only renders one selectable color. ### (Optional) Step 6: Close the color selector The `openColorSelector` method returns a `Promise` that, once resolved, returns a function. This function closes the color selector flyout: ```tsx // Open the color selector const closeColorSelector = await openColorSelector(anchor, { scopes: ["solid"], onColorSelect: (event) => { if (event.selection.type === "solid") { setColor(event.selection.hexString); } }, }); // Close the color selector closeColorSelector(); ``` Most apps don't need to call this function. The color selector automatically closes when the user clicks outside of the flyout, and this is usually the best behavior. Even so, this function is sometimes a useful escape hatch. To use this function, it often makes sense to store the function in a state variable so that it can be called throughout the lifecycle of the app. To store and then call the function from a state variable: 1. Import the `CloseColorSelectorFn` type: ```tsx import { CloseColorSelectorFn, openColorSelector } from "@canva/asset"; ``` 2. Create a state variable for storing the function: ```tsx const [closeColorSelector, setCloseColorSelector] = setState(); ``` 3. Store the function returned by the `openColorSelector` method: ```tsx const closingFn = await openColorSelector(anchor, { scopes: ["solid"], onColorSelect: (event) => { if (event.selection.type === "solid") { setColor(event.selection.hexString); } }, }); setCloseColorSelectorFn(() => closingFn); ``` **Warning:** If you set a state variable to a function, React will assume the function is an initializer function. You can account for this behavior by passing in an arrow function. To learn more, see [the official docs](https://react.dev/reference/react/useState#im-trying-to-set-state-to-a-function-but-it-gets-called-instead). 4. Elsewhere in the app, call the `closeColorSelector` method: ```tsx closeColorSelector?.(); ``` Here, we're using the `?` symbol because `closeColorSelector` will be `undefined` until the color selector is opened for the first time. ## API reference * [`openColorSelector`](https://www.canva.dev/docs/apps/api/latest/asset-open-color-selector/) ## Code sample ```tsx import { Rows, Swatch } from "@canva/app-ui-kit"; import { openColorSelector } from "@canva/asset"; import * as React from "react"; import * as styles from "styles/components.css"; import { useFeatureSupport } from "@canva/app-hooks"; export function App() { const [color, setColor] = React.useState("#ff0099"); const isSupported = useFeatureSupport(); async function handleClick(event) { if (isSupported(openColorSelector)) { const anchor = event.currentTarget.getBoundingClientRect(); await openColorSelector(anchor, { scopes: ["solid"], onColorSelect: (event) => { if (event.selection.type === "solid") { setColor(event.selection.hexString); } }, }); } } return (
); } ```