PromoBanner
Dismissible announcement banner at top of page.
Usage
import { PromoBanner } from '@/components/landing';
// In your page
const showBanner = true;
<>
{showBanner && <PromoBanner />}
<Navbar hasBanner={showBanner} />
</>
Location: src/components/landing/PromoBanner.tsx
Features
- Dismissible (X button)
- Link support
- Works with Navbar offset
Integration with Navbar
When using PromoBanner, pass hasBanner={true} to Navbar for proper positioning:
export default function LandingPage() {
const [showBanner, setShowBanner] = useState(true);
return (
<div className="min-h-screen">
{showBanner && (
<PromoBanner onDismiss={() => setShowBanner(false)} />
)}
<Navbar hasBanner={showBanner} />
<Hero />
</div>
);
}
Props
| Prop | Type | Default | Description |
|---|---|---|---|
onDismiss |
() => void |
- | Callback when banner is dismissed |
Customization
i18n
Update translations:
{
"landing": {
"promoBanner": {
"text": "New: Check out our latest feature release",
"linkText": "Learn more",
"linkUrl": "/changelog"
}
}
}
Example Implementation
'use client';
import { useState } from 'react';
import Link from 'next/link';
import { useTranslations } from 'next-intl';
import { XMarkIcon } from '@/components/icons';
interface PromoBannerProps {
onDismiss?: () => void;
}
export default function PromoBanner({ onDismiss }: PromoBannerProps) {
const t = useTranslations('landing.promoBanner');
const [isVisible, setIsVisible] = useState(true);
const handleDismiss = () => {
setIsVisible(false);
onDismiss?.();
};
if (!isVisible) return null;
return (
<div className="bg-zinc-900 dark:bg-zinc-800 text-white py-2 px-4">
<div className="container mx-auto flex items-center justify-center gap-4">
<p className="text-sm">
{t('text')}{' '}
<Link
href={t('linkUrl')}
className="underline hover:no-underline font-medium"
>
{t('linkText')} →
</Link>
</p>
<button
onClick={handleDismiss}
className="p-1 hover:bg-zinc-800 dark:hover:bg-zinc-700 rounded"
aria-label="Dismiss banner"
>
<XMarkIcon className="w-4 h-4" />
</button>
</div>
</div>
);
}
Persistence
To remember dismissal across sessions:
import { useState, useEffect } from 'react';
export default function PromoBanner() {
const [isVisible, setIsVisible] = useState(false);
useEffect(() => {
const dismissed = localStorage.getItem('promo-banner-dismissed');
setIsVisible(!dismissed);
}, []);
const handleDismiss = () => {
setIsVisible(false);
localStorage.setItem('promo-banner-dismissed', 'true');
};
if (!isVisible) return null;
return (
// ... banner content
);
}
Styling Variants
Gradient Background
className="bg-gradient-to-r from-blue-600 to-purple-600 text-white"
With Icon
<div className="flex items-center gap-2">
<SparklesIcon className="w-4 h-4" />
<span>{t('text')}</span>
</div>
Countdown Timer
For limited-time offers:
<span className="font-mono">
Ends in: {days}d {hours}h {minutes}m
</span>