JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 34
  • Score
    100M100P100Q57285F
  • License MIT

A customizable React disclaimer modal component with theme support

Package Exports

  • @citiwave/im-disclaimer-modal

Readme

@citiwave/im-disclaimer-modal

A customizable React disclaimer modal component with theme support. This component is designed to enhance user experience by providing clear and responsive terms agreements.

Installation

To install the package, use one of the following commands:

npm install @citiwave/im-disclaimer-modal
# or
yarn add @citiwave/im-disclaimer-modal

Quick Start

The package works with both JavaScript (JSX) and TypeScript (TSX) files. Import the styles based on your bundler:

// For Vite
import '@citiwave/im-disclaimer-modal/styles.css';

// For webpack or other bundlers
import '@citiwave/im-disclaimer-modal/style.css';

JavaScript (JSX)

import { DisclaimerProvider } from '@citiwave/im-disclaimer-modal';

function App() {
  const disclaimerSections = [
    {
      title: 'Terms of Service',
      required: true,
      content: <div>Your terms content here...</div>
    }
  ];

  return (
    <DisclaimerProvider
      id="my-disclaimer"           // Unique ID for localStorage
      title="Agreement Required"   // Modal title
      disclaimerSections={disclaimerSections}
      theme="light"               // or "dark"
    />
  );
}

export default App;

TypeScript (TSX)

import { DisclaimerProvider, type DisclaimerSection } from '@citiwave/im-disclaimer-modal';

const App: React.FC = () => {
  const disclaimerSections: DisclaimerSection[] = [
    {
      title: 'Terms of Service',
      required: true,
      content: <div>Your terms content here...</div>
    }
  ];

  return (
    <DisclaimerProvider
      id="my-disclaimer"
      title="Agreement Required"
      disclaimerSections={disclaimerSections}
      theme="light"
    />
  );
};

export default App;

The modal will automatically:

  • Show on first visit
  • Save the user's choice in localStorage
  • Hide after acceptance
  • Not show again on future visits

Advanced Usage

For more control over the modal's behavior, you can use the lower-level components:

Using useDisclaimer Hook

import { DisclaimerModal, useDisclaimer } from '@citiwave/im-disclaimer-modal';
import '@citiwave/im-disclaimer-modal/style.css';

const MyComponent = () => {
  const { isOpen, onClose, reset } = useDisclaimer('unique-id', {
    storagePrefix: 'my-app',
    defaultOpen: true
  });

  return (
    <DisclaimerModal
      isOpen={isOpen}
      onClose={onClose}
      title="Agreement Required"
      disclaimerSections={[...]}
      theme="light"
    />
  );
};

Requirements

To render the DisclaimerModal correctly, the following dependencies are required:

  • lucide-react version ^0.475.0 or higher.

If the required version of lucide-react is not available, the modal will automatically use fallback icons to ensure functionality.

Fallback Icons

In case the lucide-react library cannot be resolved, the modal will display default icons to maintain usability. This ensures that the modal remains functional even if the required icons are not available.

Features

  • Dark and Light theme support
  • Responsive design for all devices
  • TypeScript support
  • Customizable themes to match your application
  • Local storage persistence for user preferences
  • Smooth animations for a better user experience
  • Multi-section support for comprehensive agreements
  • JSON-based content structure
  • Content rendering utilities for dynamic content

Usage

The DisclaimerModal will automatically display on page load for first-time visitors. Once a user accepts the disclaimer, their choice is saved in localStorage and the modal won't show again unless explicitly reset.

Basic Usage with JSON Content

import { DisclaimerModal, useDisclaimer } from '@citiwave/im-disclaimer-modal';
import '@citiwave/im-disclaimer-modal/style.css'; // Required: Import the styles

const MyComponent = () => {
  // The modal will automatically show on first visit
  const { isOpen, onClose } = useDisclaimer('unique-id', {
    storagePrefix: 'my-app',  // Optional: prefix for localStorage key
    defaultOpen: true         // Optional: controls initial state for new visitors (default: true)
  });

  // Your JSON content structure
  const disclaimerContent = {
    "terms": {
      "title": "Terms",
      "required": true,
      "content": {
        "title": "Important Information",
        "sections": [
          {
            "heading": "Forward-Looking Statements",
            "text": "Your disclaimer text here..."
          },
          {
            "heading": "Additional Terms",
            "text": "More terms...",
            "list": [
              "Item 1",
              "Item 2",
              "Item 3"
            ]
          }
        ]
      }
    }
  };

  // Transform the disclaimer sections
  const disclaimerSections = Object.entries(disclaimerContent).map(([key, section]) => ({
    title: section.title,
    required: section.required,
    content: renderDisclaimerContent(section.content, 'light') // or 'dark' for dark theme
  }));

  return (
    <DisclaimerModal
      isOpen={isOpen}
      onClose={onClose}
      title="Agreement Required"
      disclaimerSections={disclaimerSections}
      theme="light" // or "dark"
    />
  );
};

Simple Usage with Static Content

For simpler use cases, you can also use static content:

import { DisclaimerModal, useDisclaimer } from '@citiwave/im-disclaimer-modal';

const MyComponent = () => {
  const { isOpen, onClose } = useDisclaimer('unique-id', {
    storagePrefix: 'my-app',
    defaultOpen: true
  });

  const disclaimerSections = [
    {
      title: 'Terms of Service',
      required: true,
      content: <div>Your terms content here...</div>
    },
    {
      title: 'Privacy Policy',
      required: false,
      content: <div>Your privacy policy content here...</div>
    }
  ];

  return (
    <DisclaimerModal
      isOpen={isOpen}
      onClose={onClose}
      title="Agreement Required"
      disclaimerSections={disclaimerSections}
      theme="light" // or "dark"
    />
  );
};

Controlling Modal Visibility

The modal has three visibility states:

  1. First Visit: Shows automatically (controlled by defaultOpen, defaults to true)
  2. After Acceptance: Hidden (stored in localStorage)
  3. Manual Control: Can be reset using the reset() function
const MyComponent = () => {
  const { isOpen, onClose, reset } = useDisclaimer('unique-id');

  // Use this to manually show the modal again
  const handleReset = () => {
    reset(); // Clears localStorage and shows the modal
  };

  return (
    <>
      <DisclaimerModal
        isOpen={isOpen}
        onClose={onClose}
        title="Agreement Required"
        disclaimerSections={[...]}
      />
      
      {/* Optional: Button to show the modal again */}
      <button onClick={handleReset}>Show Agreement</button>
    </>
  );
};

Next.js Usage

Works in both .jsx/.js and .tsx/.ts pages:

JavaScript Pages (pages/example.js)

import { DisclaimerProvider } from '@citiwave/im-disclaimer-modal';

export default function ExamplePage() {
  return (
    <>
      <h1>Your Content</h1>
      <DisclaimerProvider
        id="page-disclaimer"
        title="Important Notice"
        disclaimerSections={[
          {
            title: 'Terms',
            required: true,
            content: <div>Terms content...</div>
          }
        ]}
      />
    </>
  );
}

TypeScript Pages (pages/example.tsx)

import type { NextPage } from 'next';
import { DisclaimerProvider, type DisclaimerSection } from '@citiwave/im-disclaimer-modal';

const ExamplePage: NextPage = () => {
  const sections: DisclaimerSection[] = [
    {
      title: 'Terms',
      required: true,
      content: <div>Terms content...</div>
    }
  ];

  return (
    <>
      <h1>Your Content</h1>
      <DisclaimerProvider
        id="page-disclaimer"
        title="Important Notice"
        disclaimerSections={sections}
      />
    </>
  );
};

export default ExamplePage;

Best Practices for Both

  1. Unique IDs: Always use unique IDs to prevent conflicts
// Good 
<DisclaimerProvider id="privacy-notice" ... />
<DisclaimerProvider id="terms-notice" ... />

// Bad 
<DisclaimerProvider id="disclaimer" ... />
<DisclaimerProvider id="disclaimer" ... />
  1. Import Styles: Don't forget to import the CSS file
import '@citiwave/im-disclaimer-modal/style.css';
  1. Component Placement: Place the provider high in your component tree
// Good - In _app.js/tsx or layout component
function App() {
  return (
    <>
      <DisclaimerProvider ... />
      {/* Other components */}
    </>
  );
}

// Also Good - In specific pages when needed
function TermsPage() {
  return (
    <>
      <DisclaimerProvider ... />
      {/* Page content */}
    </>
  );
}

Usage in Next.js

In Pages or Components

The modal works seamlessly in both Next.js pages and components. For pages, make sure to use the DisclaimerProvider:

// pages/your-page.tsx
import { DisclaimerProvider } from '@citiwave/im-disclaimer-modal';
import '@citiwave/im-disclaimer-modal/style.css';

export default function YourPage() {
  return (
    <>
      {/* Your page content */}
      <DisclaimerProvider
        id="page-disclaimer"
        title="Important Notice"
        disclaimerSections={[
          {
            title: 'Terms of Service',
            required: true,
            content: <div>Your terms content here...</div>
          }
        ]}
      />
    </>
  );
}

Best Practices

  1. Place in Layout: For site-wide disclaimers, place the DisclaimerProvider in your layout component:
// components/Layout.tsx
import { DisclaimerProvider } from '@citiwave/im-disclaimer-modal';

export default function Layout({ children }) {
  return (
    <>
      {children}
      <DisclaimerProvider
        id="site-disclaimer"
        title="Site Terms"
        disclaimerSections={[...]}
      />
    </>
  );
}
  1. Page-Specific Disclaimers: For page-specific disclaimers, place the DisclaimerProvider at the page level:
// pages/sensitive-page.tsx
import { DisclaimerProvider } from '@citiwave/im-disclaimer-modal';

export default function SensitivePage() {
  return (
    <div>
      <h1>Sensitive Content</h1>
      <DisclaimerProvider
        id="sensitive-content-disclaimer"
        title="Content Warning"
        disclaimerSections={[...]}
      />
    </div>
  );
}
  1. Unique IDs: Always use unique IDs for different disclaimers to prevent conflicts:
// Good 
<DisclaimerProvider id="privacy-notice" ... />
<DisclaimerProvider id="terms-notice" ... />

// Bad 
<DisclaimerProvider id="disclaimer" ... />
<DisclaimerProvider id="disclaimer" ... />

Usage in TypeScript

The package is fully typed and works seamlessly with TypeScript. Here's how to use it in .tsx files:

import { DisclaimerProvider, DisclaimerSection } from '@citiwave/im-disclaimer-modal';
import '@citiwave/im-disclaimer-modal/style.css';

const YourPage: React.FC = () => {
  const disclaimerSections: DisclaimerSection[] = [
    {
      title: 'Terms of Service',
      required: true,
      content: <div>Your terms content here...</div>
    }
  ];

  return (
    <>
      <h1>Your Page Content</h1>
      <DisclaimerProvider
        id="page-disclaimer"
        title="Important Notice"
        disclaimerSections={disclaimerSections}
      />
    </>
  );
};

export default YourPage;

With Next.js Pages

// pages/your-page.tsx
import type { NextPage } from 'next';
import { DisclaimerProvider, DisclaimerSection } from '@citiwave/im-disclaimer-modal';
import '@citiwave/im-disclaimer-modal/style.css';

const YourPage: NextPage = () => {
  const disclaimerSections: DisclaimerSection[] = [
    {
      title: 'Terms of Service',
      required: true,
      content: <div>Your terms content here...</div>
    }
  ];

  return (
    <>
      <h1>Your Page Content</h1>
      <DisclaimerProvider
        id="page-disclaimer"
        title="Important Notice"
        disclaimerSections={disclaimerSections}
      />
    </>
  );
};

export default YourPage;

Common Mistakes

Incorrect Usage: Using as a Constructor

// This is WRONG! Don't do this:
const modal = new DisclaimerModal({
  title: "Agreement Required",
  disclaimerSections: [...],
  theme: "light"
});

Correct Usage: Using as a React Component

// This is the correct way:
import { DisclaimerModal, useDisclaimer } from '@citiwave/im-disclaimer-modal';
import '@citiwave/im-disclaimer-modal/style.css'; // Don't forget to import the styles!

const MyComponent = () => {
  const { isOpen, onClose } = useDisclaimer('unique-id');
  
  return (
    <DisclaimerModal
      isOpen={isOpen}
      onClose={onClose}
      title="Agreement Required"
      disclaimerSections={[...]}
      theme="light"
    />
  );
};

Remember:

  • DisclaimerModal is a React component, use it with JSX syntax (<DisclaimerModal />)
  • Always import and use the useDisclaimer hook to manage the modal's state
  • Don't forget to import the CSS file

Props

Prop Type Default Description
isOpen boolean false Controls the visibility of the modal
onClose function - Callback function when modal is closed
title string - Modal title
disclaimerSections array [] Array of sections to display
theme string 'light' Theme of the modal ('light' or 'dark')

useDisclaimer Hook Props

Prop Type Default Description
id string - Unique identifier for the disclaimer
options.storagePrefix string - Prefix for local storage key
options.defaultOpen boolean true Initial open state

License

MIT