Skip to main content
CanAccess is a component that wraps content and conditionally renders it based on access control permissions. It internally uses the useCan hook to check permissions.

Usage

import { CanAccess } from "@refinedev/core";

<CanAccess
  resource="posts"
  action="edit"
  params={{ id: 1 }}
  fallback={<div>Access Denied</div>}
>
  <EditButton />
</CanAccess>

Props

Examples

Basic Usage

Conditionally render an edit button:
import { CanAccess } from "@refinedev/core";

<CanAccess resource="posts" action="edit" params={{ id: 1 }}>
  <EditButton />
</CanAccess>

With Fallback

Show a message when access is denied:
import { CanAccess } from "@refinedev/core";

<CanAccess
  resource="posts"
  action="delete"
  params={{ id: 1 }}
  fallback={<div>You don't have permission to delete this post</div>}
>
  <DeleteButton />
</CanAccess>

With onUnauthorized Callback

Log unauthorized access attempts:
import { CanAccess } from "@refinedev/core";

const MyComponent = () => {
  const handleUnauthorized = ({ resource, action, reason }) => {
    console.log(`Unauthorized: ${action} on ${resource}`);
    console.log(`Reason: ${reason}`);
    // You could also show a notification or redirect
  };

  return (
    <CanAccess
      resource="posts"
      action="edit"
      params={{ id: 1 }}
      onUnauthorized={handleUnauthorized}
    >
      <EditButton />
    </CanAccess>
  );
};

Auto-detecting Resource and Action

When used within a Refine page, resource and action can be inferred from the route:
import { CanAccess } from "@refinedev/core";

// On the /posts/edit/1 page
const PostEdit = () => {
  // Resource and action are automatically inferred
  return (
    <CanAccess fallback={<div>Access Denied</div>}>
      <EditForm />
    </CanAccess>
  );
};

Passing Props to Children

Additional props are cloned to the child element:
import { CanAccess } from "@refinedev/core";

<CanAccess
  resource="posts"
  action="edit"
  params={{ id: 1 }}
  data-testid="edit-button"
  className="custom-class"
>
  <button>Edit</button>
</CanAccess>
// The button will receive data-testid and className props

Multiple Actions

Check multiple permissions:
import { CanAccess } from "@refinedev/core";

const PostActions = ({ postId }: { postId: number }) => {
  return (
    <div>
      <CanAccess resource="posts" action="edit" params={{ id: postId }}>
        <EditButton />
      </CanAccess>

      <CanAccess resource="posts" action="delete" params={{ id: postId }}>
        <DeleteButton />
      </CanAccess>

      <CanAccess resource="posts" action="show" params={{ id: postId }}>
        <ShowButton />
      </CanAccess>
    </div>
  );
};

With Custom Parameters

Pass additional context to your access control provider:
import { CanAccess } from "@refinedev/core";

const PostItem = ({ post }: { post: Post }) => {
  return (
    <CanAccess
      resource="posts"
      action="edit"
      params={{
        id: post.id,
        authorId: post.authorId,
        status: post.status,
      }}
      fallback={<div>Only the author can edit this post</div>}
    >
      <EditButton />
    </CanAccess>
  );
};

Complex Fallback UI

Render rich fallback content:
import { CanAccess } from "@refinedev/core";
import { Alert, Button } from "your-ui-library";

<CanAccess
  resource="posts"
  action="create"
  fallback={
    <Alert severity="warning">
      <h3>Insufficient Permissions</h3>
      <p>You need to upgrade your account to create posts.</p>
      <Button>Upgrade Now</Button>
    </Alert>
  }
>
  <CreateButton />
</CanAccess>

Nested CanAccess Components

Create complex permission hierarchies:
import { CanAccess } from "@refinedev/core";

const Dashboard = () => {
  return (
    <CanAccess resource="dashboard" action="view">
      <div>
        <h1>Dashboard</h1>

        <CanAccess resource="analytics" action="view">
          <AnalyticsWidget />
        </CanAccess>

        <CanAccess resource="reports" action="view">
          <ReportsWidget />
        </CanAccess>
      </div>
    </CanAccess>
  );
};

With Custom Query Options

import { CanAccess } from "@refinedev/core";

<CanAccess
  resource="posts"
  action="edit"
  params={{ id: 1 }}
  queryOptions={{
    gcTime: 300000, // Cache for 5 minutes
    staleTime: 60000, // Consider fresh for 1 minute
  }}
>
  <EditButton />
</CanAccess>

Behavior

  • When can returns true, the children are rendered
  • When can returns false:
    • The fallback is rendered if provided
    • The onUnauthorized callback is called if provided
    • null is rendered if no fallback is provided
  • If the child is a valid React element, additional props passed to CanAccess are cloned to the child
  • If the child is not a valid React element (e.g., a string or fragment), it’s wrapped in a fragment
  • During the permission check, nothing is rendered (returns null)

Notes

  • The component uses useCan internally, so all the caching and query behavior from TanStack Query applies
  • If no resource or action props are provided, they will be inferred from the current route using useResourceParams
  • The onUnauthorized callback is triggered via useEffect when data?.can becomes false
  • If no access control provider is configured, the component will render its children by default

See Also

Build docs developers (and LLMs) love