RBAC Lab
Interactive playground for experimenting with role-based access control. Edit permissions live and see the RBAC engine respond in real-time.
Interactive RBAC Lab
Switch roles and toggle permissions to see how the RBAC engine evaluates access checks in real-time. This playground demonstrates the core RBAC library behavior.
A. Role & Subject
Select Role
Current Subject
{
"id": "playground-user",
"roles": [
"viewer"
]
}B. Permission Matrix Editor
Toggle permissions for the viewer role:
C. Live Preview
Raw Permission Checks (useCan hook)
can({ action: 'read', resource: 'booking' })
can({ action: 'update', resource: 'booking' })
can({ action: 'delete', resource: 'booking' })
can({ action: 'manage', resource: 'booking' })
can({ action: 'read', resource: 'user' })
can({ action: 'update', resource: 'user' })
Native HTML Elements
Input (hidden when no 'manage booking' permission)
[Hidden - no permission]
Input (disabled when no 'update booking' permission)
Input (readonly when no 'update user' permission)
Button (hidden when no 'delete booking' permission)
[Hidden - no permission]
Button (disabled when no 'update user' permission)
Dashforge Component (access prop)
TextField with access control (hides when no 'manage booking' permission)
[Hidden - no 'manage booking' permission]
ℹ️
Live editing: Toggle permissions in the matrix editor above and watch all permission checks, native HTML elements, and Dashforge components update instantly. The RBAC engine re-evaluates everything automatically.
How It Works
Understanding live permission editing and RBAC evaluation
This playground demonstrates the core RBAC library in action. Here's what happens when you interact with it:
- Role selection determines subject.roles: When you select a role, the subject's
rolesarray updates to contain that role name - Permission matrix mutates the active role definition: Each toggle in the matrix adds or removes a permission from the current role's permission array in the policy
- RbacProvider re-renders and re-evaluates checks: When the policy or subject changes, React re-renders all components inside RbacProvider, and the RBAC engine re-evaluates all permission checks
- Native HTML and Dashforge previews reflect the same RBAC engine: Both native elements (using
useCanhook) and Dashforge components (usingaccessprop) query the same underlying RBAC engine, so they always stay in sync
Here's the actual code pattern powering this playground:
import { useState, useMemo } from 'react';
import { RbacProvider, useCan, type RbacPolicy, type Subject } from '@dashforge/rbac';
function RbacLab() {
const [selectedRole, setSelectedRole] = useState('viewer');
const [permissions, setPermissions] = useState({
'booking.read': true,
'booking.update': false,
'booking.delete': false,
});
// Build subject from role
const subject: Subject = useMemo(() => ({
id: 'user',
roles: [selectedRole]
}), [selectedRole]);
// Build policy from permission state
const policy: RbacPolicy = useMemo(() => ({
roles: [{
name: selectedRole,
permissions: Object.entries(permissions)
.filter(([_, enabled]) => enabled)
.map(([key, _]) => {
const [resource, action] = key.split('.');
return { action, resource, effect: 'allow' };
})
}]
}), [selectedRole, permissions]);
return (
<RbacProvider policy={policy} subject={subject}>
{/* Raw checks */}
<PermissionCheck />
{/* Native HTML */}
<NativeElements />
{/* Dashforge components */}
<DashforgeComponents />
</RbacProvider>
);
}
function PermissionCheck() {
// Hook re-runs when policy/subject changes
const canRead = useCan({ action: 'read', resource: 'booking' });
return <div>Can read: {canRead ? 'YES' : 'NO'}</div>;
}
function NativeElements() {
const canUpdate = useCan({ action: 'update', resource: 'booking' });
return <input disabled={!canUpdate} />;
}✓
Key insight: The RBAC engine is reactive. When you toggle permissions, the policy object changes, causing RbacProvider to re-render. All useCan hooks and access props re-evaluate automatically, and UI updates immediately.