@ihtsihamtanveer/shell
v2.0.0-alpha.0
Published
Framework-agnostic Header, Footer, and Banner shell for GovTechBB sites
Readme
@ihtsihamtanveer/shell
Framework-agnostic Header, Footer, and Banner components for GovTechBB sites. Composes primitives from @govtech-bb/react and accepts your framework's Link, Image, and usePathname via a factory so the same package works in Next.js App Router, Vite + React Router, Remix, or anything else React.
Install
pnpm add @ihtsihamtanveer/shell @govtech-bb/react @govtech-bb/design@govtech-bb/react, @govtech-bb/design, react, react-dom, and tailwindcss are peer dependencies.
⚠️ Tailwind content config — REQUIRED
Tailwind tree-shakes any class it cannot find. Add the package to your @source directive (Tailwind v4 CSS-first) or content array (Tailwind v3):
/* Tailwind v4 */
@import 'tailwindcss';
@import '@govtech-bb/design';
@source '../node_modules/@ihtsihamtanveer/shell/dist/**/*.{js,mjs,cjs}';
@source '../node_modules/@govtech-bb/react/dist/**/*.js';// Tailwind v3
content: [
'./src/**/*.{ts,tsx}',
'./node_modules/@ihtsihamtanveer/shell/dist/**/*.{js,mjs,cjs}',
'./node_modules/@govtech-bb/react/dist/**/*.js',
];Usage
Next.js App Router
// src/shell.tsx
'use client';
import NextLink from 'next/link';
import NextImage from 'next/image';
import { usePathname } from 'next/navigation';
import { createShell } from '@ihtsihamtanveer/shell';
import coatOfArms from '@ihtsihamtanveer/shell/assets/coat-of-arms.png';
export const { Header, Footer, Banner } = createShell({
Link: ({ href, children, ...rest }) => (
<NextLink href={href} {...rest}>{children}</NextLink>
),
Image: NextImage,
usePathname,
coatOfArmsSrc: coatOfArms.src,
});// app/layout.tsx
import { Banner, Footer, Header } from '@/shell';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<Banner />
<Header />
<main>{children}</main>
<Footer />
</body>
</html>
);
}Vite + TanStack React Router
// src/shell.tsx
import { Link as RouterLink, useLocation } from '@tanstack/react-router';
import { createShell } from '@ihtsihamtanveer/shell';
// Bundle the asset directly via Vite's ?url loader
import coatOfArmsUrl from '@ihtsihamtanveer/shell/assets/coat-of-arms.png?url';
export const { Header, Footer, Banner } = createShell({
Link: ({ href, children, ...rest }) => (
<RouterLink to={href} {...rest}>{children}</RouterLink>
),
// No Image override needed — defaults to plain <img>
usePathname: () => useLocation().pathname,
coatOfArmsSrc: coatOfArmsUrl,
});// src/App.tsx
import { Banner, Footer, Header } from './shell';
export const App = () => (
<>
<Banner />
<Header />
<main>...</main>
<Footer />
</>
);Plain React (no router, no Next.js)
import { createShell } from '@ihtsihamtanveer/shell';
// All defaults: <a>, <img>, window.location.pathname
export const { Header, Footer, Banner } = createShell();API
createShell(adapter?)
Returns { Header, Footer, Banner, StageBanner } — components pre-configured with the framework primitives you supplied.
| Adapter key | Type | Default |
| ---------------- | --------------------------------- | ------------------------------ |
| Link | ComponentType<LinkComponentProps> | plain <a> |
| Image | ComponentType<ImageComponentProps> | plain <img> |
| usePathname | () => string | window.location.pathname |
| coatOfArmsSrc | string | none (coat-of-arms hidden) |
<Header>
| Prop | Type | Default |
| --------------- | ----------- | ---------------------- |
| navItems | NavItem[] | DEFAULT_NAV |
| homeHref | string | '/' |
| homeAriaLabel | string | 'Go to the homepage' |
<Footer>
| Prop | Type | Default |
| ----------------- | ----------- | -------------------------- |
| links | NavItem[] | DEFAULT_FOOTER_LINKS |
| copyrightYear | number | new Date().getFullYear() |
| copyrightHolder | string | 'Government of Barbados' |
<Banner>
| Prop | Type | Default |
| ------------------ | -------------------- | -------------------------------- |
| stage | 'alpha' \| 'beta' | 'alpha' |
| hideStageOnPaths | string[] | — |
| learnMoreHref | string | '/what-we-mean-by-alpha' |
| officialLabel | string | 'Official government website' |
Migrating from 1.x
In 1.x the package imported next/link / next/image / next/navigation directly, so it only worked in Next.js App Router. In 2.x those imports are removed and the consumer supplies them via createShell. The component prop API is unchanged.
- import { Header, Footer } from '@ihtsihamtanveer/shell';
- import { Banner } from '@ihtsihamtanveer/shell/client';
+ // New: create your own shell.tsx wrapper (see Usage)
+ import { Header, Footer, Banner } from '@/shell';