Managing User Preferences

As your users interact with your Admin panel, you might want to store their preferences in a persistent manner, so that when they revisit the Admin panel, they can pick right back up where they left off.

Out of the box, Payload handles the persistence of your users' preferences in a handful of ways, including:

  1. Collection List view active columns, and their order, that users define
  2. Their last active locale
  3. The "collapsed" state of blocks, on a document level, as users edit or interact with documents

Use cases

This API is used significantly for internal operations of the Admin panel, as mentioned above. But, if you're building your own React components for use in the Admin panel, you can allow users to set their own preferences in correspondence to their usage of your components. For example:

  • If you have built a "color picker", you could "remember" the last used colors that the user has set for easy access next time
  • If you've built a custom Nav component, and you've built in an "accordion-style" UI, you might want to store the collapsed state of each Nav collapsible item. This way, if an editor returns to the panel, their Nav state is persisted automatically
  • You might want to store recentlyAccessed documents to give admin editors an easy shortcut back to their recently accessed documents on the Dashboard or similar
  • Many other use cases exist. Invent your own! Give your editors an intelligent and persistent editing experience.

Database

Payload automatically creates an internally used payload-preferences collection that stores user preferences. Each document in the payload-preferences collection contains the following shape:

KeyValue
idA unique ID for each preference stored.
keyA unique key that corresponds to the preference.
user.valueThe ID of the user that is storing its preference.
user.relationToThe slug of the collection that the user is logged in as.
valueThe value of the preference. Can be any data shape that you need.
createdAtA timestamp of when the preference was created.
updatedAtA timestamp set to the last time the preference was updated.

APIs

Preferences are available to both GraphQL and REST APIs.

Adding or reading Preferences in your own components

The Payload admin panel offers a usePreferences hook. The hook is only meant for use within the admin panel itself. It provides you with two methods:

getPreference

This async method provides an easy way to retrieve a user's preferences by key. It will return a promise containing the resulting preference value.

Arguments

  • key: the key of your preference to retrieve.
setPreference

Also async, this method provides you with an easy way to set a user preference. It returns void.

Arguments:

  • key: the key of your preference to set.
  • value: the value of your preference that you're looking to set.

Example

Here is an example for how you can utilize usePreferences within your custom Admin panel components. Note - this example is not fully useful and is more just a reference for how to utilize the Preferences API. In this case, we are demonstrating how to set and retrieve a user's last used colors history within a ColorPicker or similar type component.

1
import React, { Fragment, useState, useEffect, useCallback } from 'react';
2
import { usePreferences } from 'payload/components/preferences';
3
4
const lastUsedColorsPreferenceKey = 'last-used-colors';
5
6
const CustomComponent = (props) => {
7
const { getPreference, setPreference } = usePreferences();
8
9
// Store the last used colors in local state
10
const [lastUsedColors, setLastUsedColors] = useState([]);
11
12
// Callback to add a color to the last used colors
13
const updateLastUsedColors = useCallback((color) => {
14
// First, check if color already exists in last used colors.
15
// If it already exists, there is no need to update preferences
16
const colorAlreadyExists = lastUsedColors.indexOf(color) > -1;
17
18
if (!colorAlreadyExists) {
19
const newLastUsedColors = [
20
...lastUsedColors,
21
color,
22
];
23
24
setLastUsedColors(newLastUsedColors);
25
setPreference(lastUsedColorsPreferenceKey, newLastUsedColors);
26
}
27
}, [lastUsedColors, setPreference]);
28
29
// Retrieve preferences on component mount
30
// This will only be run one time, because the `getPreference` method never changes
31
useEffect(() => {
32
const asyncGetPreference = async () => {
33
const lastUsedColorsFromPreferences = await getPreference(lastUsedColorsPreferenceKey);
34
setLastUsedColors(lastUsedColorsFromPreferences);
35
};
36
37
asyncGetPreference();
38
}, [getPreference]);
39
40
return (
41
<div>
42
<button
43
type="button"
44
onClick={() => updateLastUsedColors('red')}
45
>
46
Use red
47
</button>
48
<button
49
type="button"
50
onClick={() => updateLastUsedColors('blue')}
51
>
52
Use blue
53
</button>
54
<button
55
type="button"
56
onClick={() => updateLastUsedColors('purple')}
57
>
58
Use purple
59
</button>
60
<button
61
type="button"
62
onClick={() => updateLastUsedColors('yellow')}
63
>
64
Use yellow
65
</button>
66
{lastUsedColors && (
67
<Fragment>
68
<h5>Last used colors:</h5>
69
<ul>
70
{lastUsedColors?.map((color) => (
71
<li key={color}>
72
{color}
73
</li>
74
))}
75
</ul>
76
</Fragment>
77
)}
78
</div>
79
);
80
};
81
82
export default CustomComponent;
Next

Bundlers