Skip to content

Feature View-Only Mode

This document explains how to implement view-only mode for features that are not included in an organization's subscription.

Overview

When an organization doesn't have access to a feature, you can now allow them to view the content (read-only) while displaying a badge indicating that the feature is not included in their subscription.

Components

1. FeatureViewOnlyBadge

A badge component that displays "View Only" when a feature is not enabled. It includes a tooltip explaining that the feature is not included in the subscription.

Usage in page headers:

import { FeatureViewOnlyBadge } from "@/components/FeatureViewOnlyBadge";

<div className="flex items-center gap-2">
 <h1>Projects</h1>
 <FeatureViewOnlyBadge feature="projects" />
</div>

2. FeatureGate with allowViewOnly

The existing FeatureGate component now supports an allowViewOnly prop that allows viewing even when the feature is disabled.

Usage:

import { FeatureGate } from "@/components/FeatureGate";

<FeatureGate feature="projects" allowViewOnly={true}>
 <ProjectsPage />
</FeatureGate>

When allowViewOnly={true}: - The page is accessible even if the feature is disabled - A sticky badge banner appears at the top of the page - Interactive elements should be wrapped with FeatureViewOnlyWrapper to disable them

3. FeatureViewOnlyGate

A simpler alternative that always allows viewing with a badge when the feature is disabled.

Usage:

import { FeatureViewOnlyGate } from "@/components/FeatureViewOnlyGate";

<FeatureViewOnlyGate feature="projects">
 <ProjectsPage />
</FeatureViewOnlyGate>

4. FeatureViewOnlyWrapper

Wraps interactive elements (buttons, forms, etc.) to disable them when in view-only mode.

Usage:

import { FeatureViewOnlyWrapper } from "@/components/FeatureViewOnlyWrapper";

<FeatureViewOnlyWrapper>
 <Button onClick={handleCreate}>Create Project</Button>
</FeatureViewOnlyWrapper>

5. useFeatureViewOnly Hook

A hook to check if the current feature is in view-only mode.

Usage:

import { useFeatureViewOnly } from "@/components/FeatureGate";

function MyComponent {
 const { isViewOnly } = useFeatureViewOnly;

 return (
 <Button disabled={isViewOnly}>
 Edit
 </Button>
 );
}

Complete Example

Here's a complete example of a page with view-only support:

import { FeatureGate } from "@/components/FeatureGate";
import { FeatureViewOnlyBadge } from "@/components/FeatureViewOnlyBadge";
import { FeatureViewOnlyWrapper } from "@/components/FeatureViewOnlyWrapper";

function ProjectsPage {
 return (
 <div>
 {/* Header with badge */}
 <div className="flex items-center gap-2">
 <h1>Projects</h1>
 <FeatureViewOnlyBadge feature="projects" />
 </div>

 {/* Interactive button wrapped to disable in view-only */}
 <FeatureViewOnlyWrapper>
 <Button onClick={handleCreate}>Create Project</Button>
 </FeatureViewOnlyWrapper>

 {/* Rest of the page content */}
 </div>
 );
}

// In your route definition:
<FeatureGate feature="projects" allowViewOnly={true}>
 <ProjectsPage />
</FeatureGate>

Best Practices

  1. Always show the badge in the page header when using view-only mode
  2. Wrap interactive elements with FeatureViewOnlyWrapper to prevent actions
  3. Use the sticky banner from FeatureGate or FeatureViewOnlyGate for prominent visibility
  4. Provide clear messaging - the badge tooltip explains the limitation
  5. Consider UX - view-only mode should still provide value by showing what's available

Migration Guide

To convert an existing feature to support view-only mode:

  1. Update the route to use allowViewOnly={true}:

    <FeatureGate feature="projects" allowViewOnly={true}>
    <Projects />
    </FeatureGate>
    

  2. Add the badge to the page header:

    <FeatureViewOnlyBadge feature="projects" />
    

  3. Wrap interactive elements:

    <FeatureViewOnlyWrapper>
    <Button>Create</Button>
    </FeatureViewOnlyWrapper>
    

  4. Test with a restricted organization to verify the badge appears and interactions are disabled.