HasAccess
Render content only when the current user has the required roles or permissions, with any/all matching, a fallback and a loading placeholder.
HasAccess renders its children only when the current user passes a role and permission check. It reads the user's lists from the nearest AclProvider and throws if there is none.
Use it for markup: buttons, menu items, page sections. When you need the result as a boolean, for example to filter a list or check access in an event handler, use useAcl instead.
Import
import { HasAccess } from "@piplup/react-acl";Usage
Toggle the user's permissions and role to see how any, all, and a combined role and permission check respond.
"use client";import * as React from "react";import Alert from "@mui/material/Alert";import Checkbox from "@mui/material/Checkbox";import FormControlLabel from "@mui/material/FormControlLabel";import Stack from "@mui/material/Stack";import { AclProvider, HasAccess } from "@piplup/react-acl";const allPermissions = ["invoice:read", "invoice:write"];export default function Page() { const [permissions, setPermissions] = React.useState<string[]>(["invoice:read"]); const [isAdmin, setIsAdmin] = React.useState(false); const roles = React.useMemo(() => (isAdmin ? ["admin"] : ["member"]), [isAdmin]); const toggle = (permission: string) => setPermissions((current) => current.includes(permission) ? current.filter((p) => p !== permission) : [...current, permission], ); return ( <Stack spacing={2}> <Stack direction="row" sx={{ flexWrap: "wrap" }}> {allPermissions.map((permission) => ( <FormControlLabel key={permission} label={permission} control={ <Checkbox checked={permissions.includes(permission)} onChange={() => toggle(permission)} /> } /> ))} <FormControlLabel label="admin role" control={<Checkbox checked={isAdmin} onChange={(e) => setIsAdmin(e.target.checked)} />} /> </Stack> <AclProvider loading={false} roles={roles} permissions={permissions}> <Stack spacing={1}> {/* Default mode is "any": one matching permission is enough. */} <HasAccess permissions={allPermissions} fallback={<Alert severity="error">any: no invoice permission</Alert>} > <Alert severity="success">any: can open the invoices page</Alert> </HasAccess> {/* "all": every listed permission is required. */} <HasAccess permissions={allPermissions} validationMode={{ permissions: "all" }} fallback={<Alert severity="error">all: needs read and write</Alert>} > <Alert severity="success">all: can edit invoices</Alert> </HasAccess> {/* Roles and permissions must both pass. */} <HasAccess roles={["admin"]} permissions={["invoice:write"]} fallback={<Alert severity="error">admin + invoice:write: denied</Alert>} > <Alert severity="success">admin + invoice:write: can void invoices</Alert> </HasAccess> </Stack> </AclProvider> </Stack> );}What it renders
HasAccess renders exactly one of its three slots, checked in this order:
| Provider state | Renders | Default |
|---|---|---|
loading is true | loading | nothing |
| Check fails | fallback | nothing |
| Check passes | children | — |
No wrapper element is added around any of them.
How access is decided
roles and permissions are checked separately, and both must pass.
| Requirement | any (default) | all |
|---|---|---|
Prop omitted or [] | Passes | Passes |
["a"] | User has a | User has a |
["a", "b"] | User has a or b | User has a and b |
A few consequences:
<HasAccess>with norolesand nopermissionsrenders its children for every user once loading is done.roles={["admin"]}with nopermissionschecks only the role.roles={["admin"]} permissions={["invoice:write"]}requires theadminrole and theinvoice:writepermission. To allow either one, use twoHasAccessblocks oruseAcl.- Values are compared with
===, so1and"1"are different.
Set the mode for each list with validationMode. A key you leave out uses any:
<HasAccess
roles={["editor", "owner"]}
permissions={["post:publish", "post:schedule"]}
validationMode={{ permissions: "all" }}
>
{/* editor OR owner, AND both post:publish and post:schedule */}
<PublishMenu />
</HasAccess>HasAccess hides UI. It does not protect data. Anything the user must not access also needs a check on your server.
Props
Prop
Type