Roles
Search and pick roles for an Auto Form field - one, or as many as you like.
Preview
Usage
import { z } from 'zod'
import { AutoForm } from '@vitnode/core/components/form/auto-form'
import { AutoFormRoles } from '@vitnode/core/components/form/fields/input-roles'One component covers both shapes, because the difference is the value and nothing else - the search, the colour, the language resolution and the empty state are identical, and two copies is how they drift.
const formSchema = z.object({
roleId: z.number(),
})<AutoForm
formSchema={formSchema}
fields={[
{
id: 'roleId',
component: (props) => (
<AutoFormRoles
{...props}
description="One role, replaced each time you pick."
label="Primary role"
placeholder="Select a role"
/>
),
},
]}
/>The value is a single id, and picking again replaces it.
const formSchema = z.object({
roleIds: z.array(z.number()).min(1),
})<AutoForm
formSchema={formSchema}
fields={[
{
id: 'roleIds',
component: (props) => (
<AutoFormRoles
{...props}
label="Additional roles"
multiple
placeholder="Add a role"
/>
),
},
]}
/>The value is an array of ids. Chosen roles appear above the picker as removable chips, and the picker appends rather than replaces - picking one that is already chosen removes it, which is what the tick beside it in the list means.
Out of the box it searches the AdminCP roles list. The guest role is never offered: it is the role a request has when it has no account, so it is not something to assign to anybody.
Editing an existing record
Same rule as User: the picker can only name ids it has seen, so an edit form passes the roles it already knows about.
<AutoFormRoles {...props} multiple label="Roles" selected={user.roles} />Keeping a role out of the list
excludeIds drops options another field already owns - a primary-role picker
and a secondary-role picker should not both offer the same one:
<AutoFormRoles
{...props}
multiple
excludeIds={[primaryRoleId]}
label="Additional roles"
/>Names are resolved per reader
A role carries one name per language. The field renders the active locale's, and falls back to the first translation rather than to the id - a role with no translation in your language is still a role somebody named:
import { roleOptionName } from '@vitnode/core/components/form/fields/input-roles'
roleOptionName(role, 'pl') // "Administrator PL", or the first name it hasProps
| Prop | Type | Default | What it does |
|---|---|---|---|
multiple | boolean | false | number[] instead of number, with chips |
label | ReactNode | - | Field label |
description | ReactNode | - | Help text under the control |
placeholder | string | Select an option | Shown while nothing is chosen |
searchPlaceholder | string | Search... | Placeholder inside the search box |
selected | RoleOption[] | [] | Roles the field opens on |
excludeIds | number[] | [] | Roles the picker must not offer |
search | (value: string) => Promise<RoleOption[]> | AdminCP roles list | Replaces the lookup |
disabled | boolean | false | Blocks opening the picker and removing chips |
RoleOption is { id, color, name }, where name is the raw
{ languageCode, name }[] - the server has no business deciding which language
the person clicking reads in.