TourKit
@tour-kit/announcementsComponents

AnnouncementModal

AnnouncementModal component: centered dialog overlay for important product updates with title, body, and action buttons

AnnouncementModal

A centered modal dialog with overlay backdrop. Best for critical announcements that require user attention.

When to Use

  • Critical security updates
  • Breaking changes
  • Important feature releases
  • User action required
  • Major product announcements

Basic Usage

import { AnnouncementsProvider, AnnouncementModal } from '@tour-kit/announcements';

const announcements = [
  {
    id: 'security-update',
    variant: 'modal',
    title: 'Security Update Required',
    description: 'Please update your password to continue using the app.',
    primaryAction: {
      label: 'Update Now',
      onClick: () => router.push('/settings/security'),
    },
  },
];

function App() {
  return (
    <AnnouncementsProvider announcements={announcements}>
      <AnnouncementModal id="security-update" />
      <YourApp />
    </AnnouncementsProvider>
  );
}

Props

Prop

Type


Configure modal behavior in the announcement config:

{
  id: 'announcement',
  variant: 'modal',
  modalOptions: {
    size: 'md', // 'sm' | 'md' | 'lg' | 'xl'
    closeOnOverlayClick: true,
    closeOnEscape: true,
    showCloseButton: true,
  },
}

ModalOptions

Prop

Type


Complete Example

const announcements = [
  {
    id: 'feature-launch',
    variant: 'modal',
    priority: 'high',
    title: 'New Export Feature',
    description: 'Export your data to CSV, PDF, or Excel format.',

    media: {
      type: 'image',
      src: '/export-preview.png',
      alt: 'Export feature preview',
    },

    primaryAction: {
      label: 'Try It Now',
      onClick: () => router.push('/export'),
    },

    secondaryAction: {
      label: 'Learn More',
      onClick: () => window.open('/docs/export'),
    },

    modalOptions: {
      size: 'lg',
      closeOnOverlayClick: false, // Prevent accidental closing
      showCloseButton: true,
    },

    frequency: 'once',
    onShow: () => analytics.track('modal_shown'),
    onDismiss: (reason) => analytics.track('modal_dismissed', { reason }),
  },
];

<AnnouncementModal id="feature-launch" />

With Media

Display images or videos in the modal:

{
  id: 'video-announcement',
  variant: 'modal',
  title: 'Product Demo',
  description: 'Watch how the new feature works.',

  media: {
    type: 'video',
    src: '/demo.mp4',
    poster: '/demo-poster.jpg',
  },

  modalOptions: {
    size: 'xl', // Larger for video
  },
}

Preventing Dismissal

For critical modals that require user action:

{
  id: 'terms-update',
  variant: 'modal',
  title: 'Terms of Service Update',
  description: 'Please accept the updated terms to continue.',

  primaryAction: {
    label: 'Accept',
    onClick: () => acceptTerms(),
  },

  modalOptions: {
    closeOnOverlayClick: false,
    closeOnEscape: false,
    showCloseButton: false, // No way to dismiss without action
  },
}

Use non-dismissable modals sparingly. Always provide a clear action path for users.


Size Variants

// Small - 400px wide
{
  id: 'small',
  variant: 'modal',
  title: 'Quick Tip',
  modalOptions: { size: 'sm' },
}

// Medium (default) - 500px wide
{
  id: 'medium',
  variant: 'modal',
  title: 'Feature Update',
  modalOptions: { size: 'md' },
}

// Large - 600px wide
{
  id: 'large',
  variant: 'modal',
  title: 'Detailed Announcement',
  modalOptions: { size: 'lg' },
}

// Extra Large - 800px wide
{
  id: 'xlarge',
  variant: 'modal',
  title: 'Full Product Demo',
  modalOptions: { size: 'xl' },
}

Styling

Custom Classes

<AnnouncementModal
  id="custom"
  className="custom-modal shadow-2xl border-2 border-primary"
/>

CSS Variables

:root {
  --announcement-modal-bg: white;
  --announcement-modal-text: #1a1a1a;
  --announcement-overlay-bg: rgba(0, 0, 0, 0.5);
  --announcement-border-radius: 0.5rem;
  --announcement-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
}

.dark {
  --announcement-modal-bg: #1a1a1a;
  --announcement-modal-text: white;
  --announcement-overlay-bg: rgba(0, 0, 0, 0.7);
}

Accessibility

The modal component includes:

  • ARIA dialog role - Proper semantic role
  • Focus trap - Focus stays within modal
  • Focus restoration - Returns focus when closed
  • Keyboard support - Escape to close (if enabled)
  • Screen reader - Announced as dialog
  • Close button - Labeled "Close announcement"
// Rendered HTML structure
<div role="dialog" aria-labelledby="modal-title" aria-modal="true">
  <h2 id="modal-title">Announcement Title</h2>
  <p>Description...</p>
  <button aria-label="Close announcement">×</button>
</div>

Programmatic Control

import { useAnnouncement } from '@tour-kit/announcements';

function ModalController() {
  const modal = useAnnouncement('my-modal');

  return (
    <div>
      <button onClick={modal.show}>Open Modal</button>
      <button onClick={modal.hide}>Close Modal</button>
      <button onClick={() => modal.dismiss('programmatic')}>
        Dismiss Forever
      </button>

      <AnnouncementModal id="my-modal" />
    </div>
  );
}

TypeScript

import type { AnnouncementConfig, ModalOptions } from '@tour-kit/announcements';

const modalConfig: AnnouncementConfig = {
  id: 'typed-modal',
  variant: 'modal',
  title: 'Typed Announcement',
  modalOptions: {
    size: 'lg',
    closeOnOverlayClick: false,
  } satisfies ModalOptions,
};

On this page