npm.io
0.1.4 • Published 8h ago

@multisystemsuite/react-permission-kit

Licence
MIT
Version
0.1.4
Deps
0
Size
609 kB
Vulns
0
Weekly
0

@multisystemsuite/react-permission-kit

Enterprise-grade React Role & Permission library for React 16, 17, 18, and 19.

Framework-agnostic. Works with React Router v5/v6/v7, Next.js, Vite, CRA, Remix, and SSR.

Table of Contents

Features

  • RBAC and permission-based access control
  • Multiple roles and permissions
  • Wildcard permissions (users.*, admin.*)
  • Hierarchical permissions (inventory.stock.read)
  • Tenant, organization, and department scoping
  • Feature flags (feature.chat, feature.ai)
  • Super admin bypass
  • Permission groups
  • Dynamic permission updates
  • Async permission loading
  • JWT integration (client-side decode)
  • localStorage, sessionStorage, memory, and custom storage adapters
  • SSR, StrictMode, and Suspense compatible
  • Zero runtime dependencies
  • Fully typed TypeScript API
  • Tree-shakeable ESM + CommonJS builds

Installation

npm install @multisystemsuite/react-permission-kit
# or
yarn add @multisystemsuite/react-permission-kit
# or
pnpm add @multisystemsuite/react-permission-kit

Peer dependencies: react and react-dom (>=16.8.0)


How to Use

Step 1: Wrap your app with PermissionProvider

Always wrap your app (or layout) with PermissionProvider and pass user permissions/roles:

import { PermissionProvider } from '@multisystemsuite/react-permission-kit';

export default function App() {
  return (
    <PermissionProvider
      permissions={['users.read', 'users.create', 'dashboard.view']}
      roles={['editor']}
      tenant="company-a"
      storage="memory"   // use "memory" for SSR
    >
      <YourApp />
    </PermissionProvider>
  );
}

Load permissions from API or JWT:

<PermissionProvider
  jwt={accessToken}
  onLoad={async () => {
    const res = await fetch('/api/me/permissions');
    return res.json(); // { permissions: [], roles: [] }
  }}
  storage="localStorage"
>
  <YourApp />
</PermissionProvider>

Step 2: Check permissions

Option A — usePermission() hook (best for logic):

import { usePermission } from '@multisystemsuite/react-permission-kit';

function UserPage() {
  const { can, cannot, hasRole, hasFeature, isSuperAdmin } = usePermission();

  if (!can('users.read')) return <p>Access denied</p>;

  return (
    <div>
      {can('users.create') && <button>Create</button>}
      {hasRole('admin') && <AdminPanel />}
      {hasFeature('feature.chat') && <ChatWidget />}
      {isSuperAdmin() && <SuperAdminTools />}
    </div>
  );
}

Option B — <Can> component (best for JSX):

import { Can, Cannot } from '@multisystemsuite/react-permission-kit';

<Can permission="users.read">
  <UserList />
</Can>

<Cannot permission="users.read">
  <p>You need users.read permission</p>
</Cannot>

Option C — <Can> with modes:

{/* hide (default) | disable | readonly */}
<Can permission="users.edit" disable fallback={<span>Read only</span>}>
  <input defaultValue="John" />
</Can>

{/* multiple permissions — any (OR) or all (AND) */}
<Can permissions={['users.read', 'users.export']} mode="all">
  <ExportButton />
</Can>

Step 3: Conditional UI components
import {
  PermissionButton,
  PermissionLink,
  PermissionRender,
  PermissionCard,
  PermissionImage,
  PermissionBadge,
} from '@multisystemsuite/react-permission-kit';

{/* Button — hide | disable | readonly + tooltip + loading */}
<PermissionButton
  permission="users.create"
  hide
  tooltip="No create access"
  isLoading={saving}
  onClick={handleCreate}
>
  Create User
</PermissionButton>

{/* Link */}
<PermissionLink permission="reports.view" to="/reports">
  View Reports
</PermissionLink>

{/* Custom render */}
<PermissionRender
  permission="dashboard.view"
  feature="feature.analytics"
  render={(allowed) => (allowed ? <Dashboard /> : <UpgradeBanner />)}
/>

{/* Card with header, actions, menu */}
<PermissionCard
  permission="dashboard.analytics"
  title="Analytics"
  actions={[{ key: 'export', label: 'Export', permission: 'reports.export' }]}
>
  Chart content
</PermissionCard>

{/* Image — hide, blur, or replace */}
<PermissionImage
  permission="media.view"
  src="/photo.jpg"
  blur
  replaceWith={<span>No access</span>}
/>

{/* Badge */}
<PermissionBadge role="admin" variant="role" />
<PermissionBadge permission="users.read" variant="permission" />

Step 4: Permission Table

Auto-hides unauthorized columns and row actions. Supports pagination, sorting, filtering, selection, bulk actions, and expandable rows.

import {
  PermissionTable,
  definePermissionActions,
} from '@multisystemsuite/react-permission-kit';

const employees = [
  { id: '1', name: 'Alice', salary: 95000 },
  { id: '2', name: 'Bob', salary: 82000 },
];

function EmployeeTable() {
  return (
    <PermissionTable
      permission="employees.view"       // hide entire table if denied
      data={employees}
      rowKey="id"
      columns={[
        { key: 'name', title: 'Name', sortable: true },
        {
          key: 'salary',
          title: 'Salary',
          permission: 'employee.salary.view',  // column auto-hidden
        },
      ]}
      actions={definePermissionActions([
        { key: 'view', label: 'View', permission: 'employee.read' },
        { key: 'edit', label: 'Edit', permission: 'employee.update' },
        { key: 'delete', label: 'Delete', permission: 'employee.delete' },
      ])}
      actionDisplay="dropdown"        // inline | dropdown | menu
      bulkActions={[
        { key: 'approve', label: 'Approve', permission: 'employee.approve' },
      ]}
      pagination={{ pageSize: 10 }}
      sortable
      filterable
      selectable
      loading={false}
      emptyText="No employees"
    />
  );
}

What happens automatically:

  • Columns with permission are hidden if user lacks access
  • Row action buttons are filtered by permission
  • Empty action column is removed when no actions are allowed
  • Bulk actions appear when rows are selected

Step 5: Permission HTML tags

Every HTML element has a permission wrapper — use instead of raw <div>, <span>, etc.

import {
  PermissionDiv,
  PermissionSpan,
  PermissionH1,
  PermissionUl,
  PermissionLi,
  PermissionAnchor,
  PermissionInputEl,
  PermissionWrapper,
  createPermissionElement,
} from '@multisystemsuite/react-permission-kit';

<PermissionDiv permission="dashboard.view" className="page">
  <PermissionH1 permission="dashboard.view">Dashboard</PermissionH1>

  <PermissionUl>
    <PermissionLi permission="users.read">Users</PermissionLi>
    <PermissionLi permission="reports.read">Reports</PermissionLi>
  </PermissionUl>

  <PermissionAnchor permission="admin.link" href="/admin">
    Admin Panel
  </PermissionAnchor>

  <PermissionInputEl permission="users.edit" type="text" placeholder="Name" />
</PermissionDiv>

{/* Any HTML tag via `as` prop */}
<PermissionWrapper as="nav" permission="nav.view">
  <a href="/">Home</a>
</PermissionWrapper>

{/* Create custom tag wrapper */}
const PermissionMark = createPermissionElement('mark');
<PermissionMark permission="highlight">Important text</PermissionMark>

Common tags: PermissionDiv, PermissionSpan, PermissionP, PermissionH1H6, PermissionUl, PermissionOl, PermissionLi, PermissionNav, PermissionHeader, PermissionFooter, PermissionSectionEl, PermissionImg, PermissionFormEl.

Full list → docs/HTML_TAGS.md


Step 6: Forms & fields
import { PermissionForm, PermissionField } from '@multisystemsuite/react-permission-kit';

{/* Auto hide/disable fields from config */}
<PermissionForm
  disableMode="hide"   // hide | disable | readonly
  fields={[
    { name: 'name', permission: 'employee.edit', label: 'Name' },
    { name: 'salary', permission: 'employee.salary.edit', label: 'Salary' },
  ]}
  onSubmit={handleSubmit}
>
  {/* or manual fields */}
  <PermissionField
    permission="employee.salary.edit"
    readonlyPermission="employee.salary.view"
    hiddenPermission="employee.ssn.view"
    label="Salary"
  >
    <input name="salary" />
  </PermissionField>
</PermissionForm>

Step 7: Menus, tabs, modals
import {
  PermissionMenu,
  PermissionTabs,
  PermissionModal,
  PermissionDialog,
  PermissionDropdown,
  PermissionToolbar,
  PermissionSidebar,
  PermissionFAB,
} from '@multisystemsuite/react-permission-kit';

{/* Menu — unauthorized items removed automatically */}
<PermissionMenu
  items={[
    { key: 'home', label: 'Home' },
    { key: 'admin', label: 'Admin', permission: 'admin.view' },
    { key: 'reports', label: 'Reports', permission: 'reports.view' },
  ]}
/>

{/* Tabs — unauthorized tabs hidden */}
<PermissionTabs
  tabs={[
    { key: 'dash', label: 'Dashboard', permission: 'dashboard.view', children: <Dashboard /> },
    { key: 'admin', label: 'Admin', permission: 'admin.view', children: <Admin /> },
  ]}
/>

{/* Modal — only opens if permission exists */}
<PermissionModal permission="users.delete" open={open} onClose={close} title="Confirm">
  Are you sure?
</PermissionModal>

{/* Dialog with confirm/cancel */}
<PermissionDialog
  permission="users.delete"
  open={open}
  message="Delete this user?"
  onConfirm={handleDelete}
  onCancel={close}
/>

{/* Toolbar actions */}
<PermissionToolbar
  actions={[
    { key: 'export', label: 'Export', permission: 'reports.export' },
    { key: 'import', label: 'Import', permission: 'reports.import' },
    { key: 'delete', label: 'Delete', permission: 'reports.delete' },
  ]}
/>

{/* Floating action button */}
<PermissionFAB permission="users.create" position="bottom-right">
  +
</PermissionFAB>

Step 8: Route guards

React Router v6/v7:

import { PermissionRoute } from '@multisystemsuite/react-permission-kit';
import { Route } from 'react-router-dom';

<Route
  path="/admin"
  element={
    <PermissionRoute
      permission="admin.access"
      redirectTo="/login"
      fallback={<p>Unauthorized</p>}
      element={<AdminPanel />}
    />
  }
/>

Next.js middleware:

// middleware.ts
import { createNextMiddlewareGuard } from '@multisystemsuite/react-permission-kit';

export const middleware = createNextMiddlewareGuard({
  publicPaths: ['/login', '/public'],
  loginPath: '/login',
  getPermissions: async (request) => {
    // decode JWT / read session and return permissions[]
    return [];
  },
});

Protected page wrapper:

import { Protected } from '@multisystemsuite/react-permission-kit';

<Protected permission="admin.access" redirectTo="/login" fallback={<AccessDenied />}>
  <AdminPage />
</Protected>

Step 9: MUI / Ant Design / other UI libraries

This package has zero UI dependencies. Wrap any third-party component:

// MUI Button with Can
import Button from '@mui/material/Button';
import { Can, usePermission } from '@multisystemsuite/react-permission-kit';

<Can permission="users.create">
  <Button variant="contained">Create</Button>
</Can>

// MUI DataGrid — filter columns with can()
const { can } = usePermission();
const columns = [
  { field: 'name', headerName: 'Name' },
  ...(can('employee.salary.view') ? [{ field: 'salary', headerName: 'Salary' }] : []),
];

// PermissionTable + MUI Chip inside cells
import Chip from '@mui/material/Chip';

<PermissionTable
  data={employees}
  rowKey="id"
  columns={[
    { key: 'name', title: 'Name' },
    {
      key: 'salary',
      title: 'Salary',
      permission: 'employee.salary.view',
      render: (v) => <Chip label={`$${v}`} size="small" />,
    },
  ]}
  actions={definePermissionActions([
    { key: 'edit', label: 'Edit', permission: 'employee.update' },
  ])}
/>

Full guides:


Quick Start

import { PermissionProvider, Can, usePermission, PermissionButton } from '@multisystemsuite/react-permission-kit';

function App() {
  return (
    <PermissionProvider
      permissions={['users.read', 'users.create', 'dashboard.view']}
      roles={['editor']}
      tenant="company-a"
      organization="india"
      department="qa"
      storage="memory"
    >
      <Dashboard />
    </PermissionProvider>
  );
}

function Dashboard() {
  const { can, cannot, hasRole, isSuperAdmin, refresh } = usePermission();

  return (
    <div>
      <Can permission="dashboard.view">
        <h1>Dashboard</h1>
      </Can>

      {can('users.read') && <UserList />}

      <PermissionButton permission="users.create" hide tooltip="No create access">
        Create User
      </PermissionButton>
    </div>
  );
}

Provider

<PermissionProvider
  permissions={[]}
  roles={[]}
  rolePermissions={{ admin: ['admin.*'], editor: ['posts.edit'] }}
  featureFlags={['feature.chat']}
  isSuperAdmin={false}
  tenant="company-a"
  organization="india"
  department="qa"
  storage="memory" // memory | localStorage | sessionStorage | custom
  storageKey="react-permission-kit"
  jwt={accessToken}
  onLoad={async () => ({ permissions: [], roles: [] })}
  onPermissionChange={(state) => console.log(state)}
>
  <App />
</PermissionProvider>

usePermission Hook

const {
  can,           // (permission: string) => boolean
  cannot,        // (permission: string) => boolean
  canAny,        // (permissions: string[]) => boolean
  canAll,        // (permissions: string[]) => boolean
  hasRole,       // (role: string) => boolean
  hasAnyRole,    // (roles: string[]) => boolean
  hasAllRoles,   // (roles: string[]) => boolean
  hasFeature,    // (feature: string) => boolean
  isSuperAdmin,  // () => boolean
  refresh,       // () => Promise<void>
  setPermissions,// (permissions: string[]) => void
  setRoles,      // (roles: string[]) => void
  loading,
} = usePermission();

Components

Component Description
<Can> Render children when allowed
<Cannot> Render when denied
<Protected> Block content with fallback/redirect
<PermissionButton> Button with hide/disable/readonly modes
<PermissionLink> Permission-aware anchor
<PermissionRoute> Router-agnostic route guard
<PermissionTable> Table with auto-filtered columns/actions
<PermissionMenu> Auto-filtered menu
<PermissionTabs> Auto-filtered tabs
<PermissionModal> Permission-gated modal
<PermissionForm> Auto hide/disable form fields

See API Documentation for the full list.

Advanced UI Components

All 20 enterprise components are included with built-in permission filtering.

PermissionTable

Auto-hides unauthorized columns and row actions. Supports selection, pagination, sorting, filtering, server-side mode, expandable rows, bulk actions, and responsive layout.

<PermissionTable
  permission="employees.view"
  data={employees}
  rowKey="id"
  columns={[
    { key: 'name', title: 'Name' },
    { key: 'salary', title: 'Salary', permission: 'employee.salary.view' },
  ]}
  actions={definePermissionActions([
    { key: 'edit', label: 'Edit', permission: 'employee.update', icon: <EditIcon /> },
    { key: 'delete', label: 'Delete', permission: 'employee.delete', danger: true },
  ])}
  actionDisplay="dropdown"   // inline | dropdown | menu
  bulkActions={[{ key: 'delete', label: 'Delete', permission: 'employee.bulk.delete' }]}
  pagination={{ pageSize: 10 }}
  sortable
  filterable
  selectable
  expandable={{ expandedRowRender: (row) => <Detail row={row} /> }}
  loading={isLoading}
  emptyText="No employees"
/>

The library automatically:

  • Removes unauthorized columns (PermissionColumn permission prop)
  • Removes unauthorized action buttons
  • Removes the actions column when no row has visible actions
  • Supports icon-only actions (iconOnly: true)
  • Supports dropdown and row menu action display
  • Supports bulk actions on selected rows
PermissionButton

Modes: hide, disable, readonly via props or hideMode. Supports tooltip, icon, and isLoading.

<PermissionButton permission="users.create" hide tooltip="No access" icon={<PlusIcon />} isLoading={saving}>
  Create
</PermissionButton>
PermissionField / PermissionForm
<PermissionForm
  disableMode="hide"
  fields={[
    { name: 'salary', permission: 'employee.salary.edit', label: 'Salary' },
    { name: 'ssn', hiddenPermission: 'employee.ssn.view' },
  ]}
/>
PermissionRender

Render by permission, role, or feature flag:

<PermissionRender
  permission="dashboard.view"
  feature="feature.analytics"
  render={(allowed) => (allowed ? <Dashboard /> : <Upgrade />)}
/>

See docs/API.md for PermissionCard, PermissionMenu, PermissionSidebar, PermissionTabs, PermissionModal, PermissionDialog, PermissionDropdown, PermissionToolbar, PermissionFAB, PermissionImage, PermissionSection, PermissionSkeleton, and PermissionBadge.

MUI, Ant Design & other UI libraries

This package has no UI dependency. Use it with MUI, Ant Design, Chakra, shadcn/ui, or any kit:

Approach Example
usePermission() Filter MUI DataGrid columns with can('employee.salary.view')
<Can> wrapper <Can permission="x"><MuiButton /></Can>
PermissionTable Permission logic + MUI Chip/Icon in column render
// MUI Button
import Button from '@mui/material/Button';
import { Can } from '@multisystemsuite/react-permission-kit';

<Can permission="users.create">
  <Button variant="contained">Create</Button>
</Can>

// PermissionTable + MUI inside cells
<PermissionTable
  data={employees}
  rowKey="id"
  columns={[
    { key: 'name', title: 'Name' },
    {
      key: 'salary',
      title: 'Salary',
      permission: 'employee.salary.view',
      render: (v) => <Chip label={`$${v}`} size="small" />,
    },
  ]}
  actions={definePermissionActions([
    { key: 'edit', label: 'Edit', permission: 'employee.update', icon: <EditIcon /> },
  ])}
/>

Full guide: docs/INTEGRATIONS.md
Examples: examples/mui/, examples/antd/, examples/chakra/, examples/shadcn/

Permission HTML tags (all elements)

Every HTML tag has a permission wrapper: PermissionDiv, PermissionSpan, PermissionH1, PermissionUl, PermissionAnchor, and 80+ more.

import { PermissionDiv, PermissionUl, PermissionLi, PermissionWrapper } from '@multisystemsuite/react-permission-kit';

<PermissionDiv permission="dashboard.view">
  <PermissionUl>
    <PermissionLi permission="users.read">Users</PermissionLi>
    <PermissionLi permission="reports.read">Reports</PermissionLi>
  </PermissionUl>
</PermissionDiv>

{/* Any tag via `as` */}
<PermissionWrapper as="nav" permission="nav.view">Menu</PermissionWrapper>

See docs/HTML_TAGS.md for the full list and createPermissionElement() factory.

Permission Engine

import { checkPermission, matchWildcard, mergePermissions } from '@multisystemsuite/react-permission-kit';

checkPermission('users.read', ['users.*']); // { allowed: true }
matchWildcard('admin.*', 'reports.export'); // true
mergePermissions(['a'], ['b']);             // ['a', 'b']
Permission Examples
  • users.read, users.create, users.update, users.delete
  • dashboard.view, reports.export
  • admin.*, users.*
  • inventory.stock.edit, sales.order.approve
  • feature.chat, feature.ai

Route Guards

React Router v6/v7
<Route
  path="/admin"
  element={
    <PermissionRoute
      permission="admin.access"
      redirectTo="/login"
      element={<AdminPanel />}
    />
  }
/>
Next.js Middleware
import { createNextMiddlewareGuard } from '@multisystemsuite/react-permission-kit';

export const middleware = createNextMiddlewareGuard({
  publicPaths: ['/login'],
  loginPath: '/login',
  getPermissions: async (request) => [],
});

SSR

Use storage="memory" on the server and hydrate with client permissions:

<PermissionProvider permissions={serverPermissions} storage="memory">
  {children}
</PermissionProvider>

Documentation

Development

npm install
npm run build
npm test
npm run test:coverage
npm run lint
npm run docs

Publishing

This package uses Changesets for versioning:

npm run changeset    # Add a changeset
npm run version-packages
npm run release      # Build and publish to npm

Set NPM_TOKEN in GitHub secrets for automated publishing via GitHub Actions.

License

MIT MultiSystemSuite

Keywords