expo-quick-actions
v2.0.0
Published
use native quick actions
Downloads
45,290
Maintainers
Readme
expo-quick-actions
This is not an official Expo SDK package.
A comprehensive React Native library for home screen quick actions.
Versioning
Ensure you use versions that work together!
| expo
| expo-quick-actions
|
| ------ | -------------------- |
| 50.0.0 | 1.0.0 |
| 49.0.0 | 0.0.0 |
API documentation
import * as QuickActions from "expo-quick-actions";
Action
The Action
type is an object with the following properties:
id: string
: A unique identifier for the action.title: string
: The title of the action.subtitle?: string | null
: The subtitle of the action, iOS-only.icon?: string | null
: Asset reference to use for the icon.params?: Record<string, number | string | boolean | null | undefined> | null
: Additional serial parameters for the action.
initial
Action | null
A static property that returns the initial quick action item that was used to open the app, if any.
const initialAction = QuickActions.initial;
maxCount
number | null
A static property that returns the maximum number of quick action items that can be set.
- On iOS, this is hardcoded to 4.
- On Android, this is dynamically collected on start-up.
// e.g. 15 on Pixel 6, null on iOS.
const maxCount = QuickActions.maxCount;
setItems
(items: Action[]) => Promise<void>
An async function that sets the quick action items for the app. Both Apple and Android recommend a max of 4 items.
QuickActions.setItems([
{
id: "0",
title: "Open Settings",
subtitle: "Go here to configure settings",
icon: "heart",
params: { href: "/settings" },
},
]);
isSupported
() => Promise<boolean>
An async function that returns whether the device supports home screen quick actions.
const isSupported = await QuickActions.isSupportedAsync();
addListener
(listener: (payload: Action) => void) => Subscription
Adds a listener that will fire when a quick action is triggered.
const subscription = QuickActions.addListener((action) => {
console.log(action);
});
Icons
Read the Android design docs for shortcut icons.
On iOS, there are three types of images you may want to use: default icons, SF Symbols, and custom template images. The icon
property supports magic prefixes to access all the built-in icons:
SF Symbols
UIApplicationShortcutIcon(systemImageName:)
-- Create an icon using a system image. You can use any of the names here that are usable with -systemImageNamed:.
Icons prefixed with symbol:
are passed to UIApplicationShortcutIcon(systemImageName:)
, e.g. symbol:heart.fill
will use UIApplicationShortcutIcon(systemImageName: "heart.fill")
which renders the SF Symbols icon named heart.fill
. Learn more about Apple SF Symbols. Note: SF Symbols are only available on iOS as Apple copyright restricts using them on other platforms.
System Icons
UIApplicationShortcutIcon(type:)
-- Create an icon using a system-defined image.
Icons matching one of the following will use a built-in icon: "compose", "play", "pause", "add", "location", "search", "share", "prohibit", "contact", "home", "markLocation", "favorite", "love", "cloud", "invitation", "confirmation", "mail", "message", "date", "time", "capturePhoto", "captureVideo", "task", "taskCompleted", "alarm", "bookmark", "shuffle", "audio", "update".
If no built-in icon is found, the icon will default to using a custom image with the same name, e.g. heart
will use UIApplicationShortcutIcon(templateImageName: "heart")
.
Custom Images
Create an icon using a system-defined image.
UIApplicationShortcutIcon(templateImageName:)
-- Create an icon from a custom image. The provided image named will be loaded from the app's bundle and will be masked to conform to the system-defined icon style.
Icons prefixed with asset:
are passed to UIApplicationShortcutIcon(templateImageName:)
, e.g. asset:heart
will use UIApplicationShortcutIcon(templateImageName: "heart")
which will load the image named heart
from the app's bundle and mask it to conform to the system-defined icon style.
Hooks
Convenience hooks are exposed with the nested import expo-quick-actions/hooks
.
import {
useQuickActionCallback,
useQuickAction,
} from "expo-quick-actions/hooks";
useQuickActionCallback
(callback: (action: Action) => void) => void
A hook that registers a callback that will fire when a quick action is triggered. This is useful for global updates like navigating or analytics.
import { useQuickActionCallback } from "expo-quick-actions/hooks";
function Route() {
useQuickActionCallback((action) => {
// Do something with the action without explicitly re-rendering the component. This is useful for global updates like navigating or analytics.
console.log(">", action);
});
}
useQuickAction
() => Action | null
A hook that returns the current quick action. This is useful for updating the UI.
import { useQuickAction } from "expo-quick-actions/hooks";
function Route() {
// Re-renders the component when the action changes. This is useful for updating the UI.
const action = useQuickAction();
}
Expo Router
The philosophy in Expo Router is to treat opening the app from the home screen as linking to "/" (index route). In the future, I'd like to account for launching from native APIs like Share Sheet invocations, Siri, Quick Actions, Notifications, etc and linking to a well-known URL convention. This isn't the case today, but I did design around it.
Pass params: { href: "..." }
and use a hook in the Layout Route to handle the invocation.
For example, using the hooks above:
// app/(root)/_layout.tsx
import { useEffect } from "react";
import { Slot } from "expo-router";
import { useQuickActionRouting, RouterAction } from "expo-quick-actions/router";
import * as QuickActions from "expo-quick-actions";
export default function Layout() {
// Enable linking to the `href` param when a quick action is used.
useQuickActionRouting();
useEffect(() => {
// Now you can configure your quick actions to link places (including externally):
QuickActions.setItems<RouterAction>([
{
title: "New Chat",
icon: "compose",
id: "0",
params: { href: "/compose" },
},
{
title: "Search",
icon: "search",
id: "1",
params: { href: "/search" },
},
{
title: "Leave Feedback",
subtitle: "Please provide feedback before deleting the app",
icon: "symbol:envelope",
id: "2",
params: { href: "mailto:[email protected]" },
},
]);
}, []);
return <Slot />;
}
This can be used with Typed Routes to ensure the params.href
can only be linked to a valid route within your project.
Config Plugin
There's an optional config plugin that you can use to add images and static iOS actions. Static Android actions are not currently supported because they don't support complex intent.
androidIcons
: An object of Android icons. The key is theicon
property of the action. The value can be a string or an object withforegroundImage
andbackgroundColor
properties. This generates very similar toandroid.adaptiveIcon
as the underlying API is very similar. For simple icons, you can use a string value.iosIcons
: An object of iOS icons. The key is theicon
property of the action. The value can be a string or an object with1x
,2x
, and3x
properties.iosActions
: An array of iOS actions. These are static actions that will be available unless you clear them with the dynamic API. Theicon
property resolves the same as in the dynamic API, usingsymbol:
andasset:
prefixes.
app.json
{
"plugins": [
[
"expo-quick-actions",
{
"androidIcons": {
"shortcut_one": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#282A35"
},
"shortcut_two": {
"foregroundImage": "./assets/adaptive-star.png",
"backgroundColor": "#ff0000"
},
"shortcut_three": "https://evanbacon.dev/pfp.png"
},
"iosIcons": {
"shortcut_one": "./assets/adaptive-icon.png",
"shortcut_two": {
"1x": "./assets/adaptive-icon.png"
}
},
"iosActions": [
{
"id": "1",
"title": "Shortcut One",
"subtitle": "Subtitle One",
"icon": "shortcut_one",
"params": {
"href": "https://evanbacon.dev"
}
}
]
}
]
]
}
iOS Best Practice
Use 4 Actions
Apple recommends using all four spots, utility-based apps like calculators will use less. If you can't think of four spots, then just make the actions deep link to a specific screen in your app.
Avoid branded icons
Use SF Symbols. While you can have custom icons on iOS (and I made it really easy via the Expo Config Plugin), opt towards using SF Symbols instead. This is because Apple injects their own actions ("Edit Home Screen", "Share App", "Remove App") and the icons will look out of place next to them––see the example below. If you absolute must use branded icons, then try to match the stroke-weight of the default icons.
If you want to use a custom icon, prefer outline icons to filled icons on iOS.
Search action
iOS apps often have a "Search" shortcut that opens the app and focuses the search bar. This is a good default shortcut to have. Make it the last item in the list. E.g. Whatsapp, Twitter, Apple Mail, Amazon, Slack.
Here's the object you can use to add a basic "Search" action:
{
"id": "search",
"title": "Search",
// Built-in icon for search
"icon": "search",
// SF Symbol equivalent
// "icon": "symbol:magnifyingglass",
"params": {
// Optional deep link to a search page (must be handled manually with something like Expo Router).
"href": "/search"
}
}
Android Best Practice
Use 4 actions Android sometimes supports more, but I read somewhere in the Google docs that 4 is recommended.
Use Adaptive Icons
Android shortcuts can be saved to the screen, iOS shortcuts cannot. This means that Android shortcuts should be thought of as alternative entry points to your app. The icon and name should reflect that. Because of this, I've made the Expo Config Plugin capable of generating full responsive app icons (as well as simple icons).
For example, if we want a "Compose" action like the one found in Gmail, that can be implemented as follows:
First, we'll add the icon and background color in the app.json
:
{
"plugins": [
[
"expo-quick-actions",
{
"androidIcons": {
"shortcut_compose": {
"foregroundImage": "./assets/adaptive-compose.png",
"backgroundColor": "#C84031"
}
}
}
]
]
}
Second, we'll add an image to our project at ./assets/adaptive-compose.png
. This will be the Material design "create" icon with about 30% padding on all sides.
Now if we run npx expo prebuild -p android
, rebuild npx expo run:android
, we can use the icon from source:
// Add the compose action
QuickActions.setItems([
{
id: "compose",
icon: "shortcut_compose",
title: "Compose",
},
]);
You can see the results below, it even has the signature "wiggle" when you move the icon around.
https://github.com/EvanBacon/expo-quick-actions/assets/9664363/b3fe7608-1700-4247-8687-0c9dc7c6025e
Troubleshooting
The icon is a small circle on iOS
This can happen if the icon
property is invalid. See how icons are resolved to learn more. If you're using a custom asset then you need to ensure all three scales are added to the asset catalog (default if only a string is passed in the Config Plugin).