npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@multisystemsuite/react-permission-kit

v0.1.7

Published

Enterprise-grade React Role & Permission library for React 16–19. RBAC, wildcards, feature flags, SSR, and router-agnostic guards.

Readme

@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:


Step 10: Custom styling

This library ships no default CSS. You control all styling with your own classes, inline styles, or UI framework.

HTML tag components (PermissionDiv, PermissionButton, etc.) accept every native HTML prop — className, style, id, data-*, and more:

<PermissionDiv
  permission="dashboard.view"
  className="page card"
  style={{ padding: 16, background: '#f5f5f5' }}
>
  Dashboard
</PermissionDiv>

<PermissionButton
  permission="users.delete"
  className="btn btn-danger"
  style={{ marginTop: 8 }}
>
  Delete
</PermissionButton>

Any HTML tag via PermissionWrapper:

<PermissionWrapper
  as="nav"
  permission="nav.view"
  className="sidebar"
  style={{ width: 240 }}
>
  Menu items
</PermissionWrapper>

Built-in UI components — pass className on the root element; button/link components also accept full native HTML attributes:

<PermissionTable className="my-table" data={rows} columns={columns} />
<PermissionCard className="card card--elevated" permission="reports.view" title="Reports" />
<PermissionModal className="modal modal--lg" permission="settings.open" title="Settings" />

Can / Cannot / Protected — no wrapper element; style the child directly:

<Can permission="reports.view">
  <div className="report-panel" style={{ minHeight: 400 }}>
    Report content
  </div>
</Can>

Third-party components (MUI, Ant Design, Chakra, shadcn) — use PermissionRender or wrap with Can and style your component as usual:

import Button from '@mui/material/Button';
import { PermissionRender } from '@multisystemsuite/react-permission-kit';

<PermissionRender
  permission="users.delete"
  render={(allowed) =>
    allowed ? (
      <Button className="mui-delete-btn" color="error" variant="contained">
        Delete
      </Button>
    ) : null
  }
/>

Custom HTML tag factory — create and style any tag:

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

const PermissionMark = createPermissionElement('mark');

<PermissionMark
  permission="highlight"
  className="highlight-yellow"
  style={{ fontWeight: 600 }}
>
  Important
</PermissionMark>

When permission is denied, interactive elements may receive data-permission-denied (and disabled / readOnly depending on deny mode) — use these for custom disabled/hidden styles in your CSS.


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