content-block-library
v0.6.10
Published
Brand-aware components for React and Next.js
Downloads
1,303
Readme
Content Block Library
This repository provides a shared content blocks intended to be used across multiple Next.js brand applications.
- SEO-friendly
- Accessible (keyboard + ARIA compliant)
- Brand-themed via CSS variables
- Fully controlled from the consuming app
What This Library Provides
FAQPage– page-level layout shell (header, sidebar, content)FAQAccordion– generic controlled accordion primitiveFAQDoubleAccordion– composed UI for section → FAQ accordion
The library does not own state or business logic. All filtering, search, routing, and CMS mapping live in the consumer app.
Package Type
This is a src-shipping shared library.
- Components are consumed as source
- SCSS Modules and CSS variables are used directly
- Consumers must transpile the package (e.g. via
transpilePackagesin Next.js)
Installation
After publishing the package internally:
npm install 'content-block-library'In the consuming Next.js app, ensure the package is transpiled:
// next.config.js
module.exports = {
transpilePackages: ['content-block-library'],
}Global Styles Import
This library ships a global styles entry point that must be imported once by the consuming application.
How to import
App Router (app/layout.tsx)
import 'content-block-library/styles/globals.scss'Notes
- Import once per app
- Do not import inside individual components
- Global styles only define CSS variables and brand overrides
Running the Example App
This repository includes an example Next.js app under examples/next-app.
Steps
From the repository root:
npm installThen:
cd examples/next-app
npm install
npm run devThe example app uses demo FAQ data and shows search, section filtering, single-section view, and double-accordion view.
FAQ Data Contract
The library defines a clean, CMS-agnostic FAQ data contract. Consumer applications must map CMS responses to these structures before rendering.
export interface FAQ {
id: string
question: string
answer: string
}
export interface FAQSection {
id: string
slug: string
heading: string
faqs: FAQ[]
}FAQrepresents a single question and answerFAQSectionrepresents a category of FAQsslugis used for SEO, anchor links, and URL syncing
Rendering Strategy (Accordion)
FAQ answers may include rich HTML, including embedded YouTube videos.
To avoid mobile WebKit crashes caused by eagerly-loaded iframes:
- FAQ content is rendered using conditional mounting:
{isOpen && <FAQAccordionBody />}- Embedded media (e.g. YouTube iframes) only exist in the DOM after the accordion is opened
- Accordion open/close transitions use true height-based animations (not CSS
max-heighthacks)
This choice explicitly prioritises runtime stability on mobile devices over fully static SSR FAQ content.
SEO Strategy
SEO for FAQ pages is handled using structured data, not SSR visibility.
Key points
- FAQ answers are not required to be visible or present in SSR HTML
- FAQ discoverability is provided via:
- Page-level
WebPageschema - Topic-scoped
FAQPageschema
- Page-level
This approach is compliant with Google’s structured data guidelines, provided schema content matches rendered content.
Schema Strategy
Each FAQ sub-page includes two linked schema entities.
1. WebPage (page-level schema)
Defines the page itself and links to its FAQ content.
{
"@context": "https://schema.org",
"@type": "WebPage",
"@id": "https://example.com/faqs/orders-returns#webpage",
"name": "Orders & Returns – FAQs",
"mainEntity": {
"@id": "https://example.com/faqs/orders-returns#faq"
}
}2. FAQPage (FAQ-level schema)
Contains only the questions shown on the current page.
- Questions are flattened (no section grouping in schema)
- Answers are text-only or simple HTML
- Embedded media is excluded from schema text
{
"@context": "https://schema.org",
"@type": "FAQPage",
"@id": "https://example.com/faqs/orders-returns#faq",
"mainEntity": [
{
"@type": "Question",
"name": "How do I return an order?",
"acceptedAnswer": {
"@type": "Answer",
"text": "You can return an order within 30 days of purchase."
}
}
]
}