fragment-headless-sdk
v2.2.0
Published
The official SDK for integrating with Fragment-Shopify CMS. Provides React components, TypeScript types, and utilities for rendering published sections in headless Shopify storefronts.
Readme
Fragment Headless SDK
The official SDK for integrating with Fragment-Shopify CMS. Provides React components, TypeScript types, and utilities for rendering published sections in headless Shopify storefronts.
✨ What's New
v2.2.0 - Google Analytics 4 (GA4) integration with automatic section tracking
See CHANGELOG.md for full release history
🏗️ Architecture
This package works as a consumer library that integrates with the Fragment-Shopify app:
Fragment-Shopify App (CMS) → API Endpoint → fragment-headless-sdk (Consumer) → Your Headless Site- Fragment-Shopify App: Content management system for creating and publishing sections
- fragment-headless-sdk: This SDK - consumes and renders the published content
- Your App: Next.js/React application that uses the SDK
🔧 Features
Core Features
- ✅ Data Fetching: Built-in utilities to fetch sections from Fragment-Shopify API
- ✅ React Components: Pre-built Hero and Announcement components with responsive design
- ✅ TypeScript Support: Full type definitions for all components and data structures
- ✅ Multiple Announcement Types: Standard, marquee, and countdown announcements
- ✅ Hero Sections: Desktop/mobile responsive hero components with video support
- ✅ Advanced Click Tracking: Separated tracking and navigation for optimal user experience
Advanced Styling System (v2.0+)
- 🎨 Structured Design Tokens: Organized color, spacing, typography, and effect tokens
- 📱 Responsive Styling: Breakpoint-specific overrides (sm, md, lg, xl, 2xl)
- 🎭 State-Based Styling: Hover, active, focus, disabled, and loading states
- 🎯 Design Token System: Structured tokens for consistent styling
- 🔧 Component-Specific Slots: Type-safe styling for individual component parts
- ⚡ Performance Optimized: Caching and memoization for optimal performance
- 🎪 CSS-in-JS Support: Integration with styled-components, emotion, etc.
Hero Resolvers System (v2.1+)
- 🔤 Advanced Typography: Built-in font family support (Roboto, Inter, Montserrat, etc.)
- 📐 Layout Controls: Content positioning (left/center/right), width, and height management
- 🎨 Smart Color Resolution: Intelligent fallback handling for color tokens
- 🛠️ Utility Functions: Helper functions for class joining, text rendering, and style resolution
- 📝 Type Safety: Enhanced TypeScript interfaces for all styling options
Request Deduplication & Performance System (v2.1.3+)
- ⚡ Smart Deduplication: Prevents identical concurrent API requests automatically
- 🚀 Optimized Caching: 60-second cache revalidation for optimal performance vs freshness
- 🔧 Consistent Parameters: Normalized parameter handling ensures reliable cache keys
- 🛡️ Anti-Spam Protection: Built-in protection against redundant API calls
- 📊 Performance Monitoring: Console logging for deduplication events and debugging
- 🔄 Graceful Fallback: Failed requests retry automatically without affecting user experience
Enhanced Click Tracking System (v2.1.1+)
- 🎯 Separated Concerns: Button destinations and click tracking handled independently
- ⚡ Direct Navigation: Users go directly to destinations without redirect delays
- 🔗 Advanced Tracking:
fireClickMetric()function with fetch API and image fallback - 🛠️ Non-Blocking: Click tracking doesn't delay user navigation
- 🌐 Cross-Browser: Works across all modern browsers with appropriate fallbacks
- 🔄 Graceful Degradation: Tracking fails silently without affecting user experience
Google Analytics 4 (GA4) Integration (v2.2.0+)
- 📊 Automatic Event Tracking: Automatic
section_viewandsection_clickevents - 🎯 Type-Safe Section Types:
SectionTypeenum for consistent section identification - 🔧 Configurable Tracking: Control tracking via
measurementId,sectionId, andsectionTypefields - ⚡ Dual Tracking: Maintains existing pixel tracking while adding GA4 support
- 🛡️ Graceful Fallback: Works even if GA4 is not configured (doesn't break functionality)
- 📦 Exported Types:
SectionTypeenum available for consumer use
📦 Installation
# Using Yarn
yarn add fragment-headless-sdk
# Using npm
npm install fragment-headless-sdk🎨 Tailwind CSS Setup
Since this package uses Tailwind utility classes, your host app must be configured with Tailwind CSS.
1. Install Tailwind
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p2. Update tailwind.config.js
const path = require("path");
module.exports = {
content: [
"./app/**/*.{js,ts,jsx,tsx,mdx}",
"./pages/**/*.{js,ts,jsx,tsx,mdx}",
"./components/**/*.{js,ts,jsx,tsx,mdx}",
path.join(
__dirname,
"node_modules/fragment-headless-sdk/dist/**/*.{js,ts,jsx,tsx}"
),
],
theme: {
extend: {},
},
plugins: [],
corePlugins: {
preflight: false,
},
};3. Include Tailwind in your global CSS
@tailwind base;
@tailwind components;
@tailwind utilities;4. Import Fragment SDK Styles
Required - Import the SDK's CSS file for proper typography and animations:
Option A: JavaScript/TypeScript Import
// In your main app file (e.g., _app.tsx, layout.tsx, or main.tsx)
import "fragment-headless-sdk/styles";Option B: CSS Import
/* In your global CSS file */
@import "fragment-headless-sdk/dist/styles/fragment-sdk.css";This provides:
- Google Fonts for all supported font families (Roboto, Inter, Montserrat, etc.)
- Marquee animations for announcement components
- Improved link styling for prose content
🚀 Quick Start
1. Fetch Data from Fragment-Shopify
import { fetchResource, ResourceType } from "fragment-headless-sdk";
// Fetch hero sections
const heroBanners = await fetchResource({
baseUrl: process.env.EXTERNAL_API_URL, // Your Fragment-Shopify app URL
apiKey: process.env.FRAGMENT_API_KEY, // API key from Fragment-Shopify (format: "keyId:secret")
type: ResourceType.HeroBanners,
});
// Fetch announcements with optional parameters
const announcements = await fetchResource({
baseUrl: process.env.EXTERNAL_API_URL,
apiKey: process.env.FRAGMENT_API_KEY,
type: ResourceType.Announcements,
params: {
status: "enabled", // Only fetch enabled announcements
limit: 10, // Limit to 10 items
search: "sale", // Search for announcements containing "sale"
},
cacheOptions: {
revalidate: 30, // Custom 30-second cache revalidation
tags: ["announcements"], // Custom cache tags
},
});2. Basic Component Usage
import { Announcement, Hero } from "fragment-headless-sdk";
import { AnnouncementType } from "fragment-headless-sdk";
export default function Page() {
const [showAnnouncement, setShowAnnouncement] = useState(true);
return (
<>
{/* Hero Section */}
<Hero content={heroBanners[0]?.content} />
{/* Announcement */}
{showAnnouncement && announcements[0] && (
<Announcement
content={announcements[0].content}
type={announcements[0].type as AnnouncementType}
handleClose={() => setShowAnnouncement(false)}
/>
)}
</>
);
}3. Advanced Styling (v2.0+)
import { Hero } from "fragment-headless-sdk";
// Enhanced styling with the new system
const heroContent = {
title: "Welcome to Our Store",
description: "Discover amazing products",
buttonText: "Shop Now",
buttonLink: "/products",
imageUrl: "https://example.com/hero.jpg",
mobileImageUrl: "https://example.com/hero-mobile.jpg",
// Advanced styling configuration
styling: {
// Structured design tokens
tokens: {
colors: {
background: "#1a1a1a",
text: "#ffffff",
title: "#f0f0f0",
button: "#007bff",
buttonText: "#ffffff",
},
spacing: {
padding: "2rem",
margin: "1rem",
},
typography: {
titleSize: "3rem",
textSize: "1.2rem",
},
},
// Component-specific slot styling
slots: {
root: {
className: "min-h-screen",
style: {
background: "linear-gradient(135deg, #667eea 0%, #764ba2 100%)",
},
},
title: {
className: "font-bold tracking-tight",
responsive: {
md: { className: "text-6xl" },
lg: { className: "text-7xl" },
},
states: {
hover: { className: "text-blue-300" },
},
},
button: {
className: "px-8 py-4 rounded-full",
style: { boxShadow: "0 10px 25px rgba(0,123,255,0.3)" },
states: {
hover: {
className: "scale-105 shadow-xl",
style: { transform: "translateY(-2px)" },
},
},
},
},
},
};
<Hero content={heroContent} />;Advanced Features: For detailed styling options, see STYLING.md | For hero customization, see HERO-RESOLVERS.md
📡 API Reference
fetchResource<T>(params)
Fetches sections from your Fragment-Shopify app with intelligent request deduplication and caching.
Parameters:
baseUrl: string- URL of your Fragment-Shopify appapiKey: string- Fragment API key (format:keyId:secret)type: ResourceType- Type of resource to fetchparams?: ListParams- Optional filtering and pagination parametersfetchImpl?: typeof fetch- Optional custom fetch implementationcacheOptions?: CacheOptions- Optional cache configuration
ListParams Options:
status?: "enabled" | "disabled"- Filter by status (defaults to "enabled")page?: number- Page number for pagination (defaults to 1)limit?: number- Items per page (defaults to 25, max 100)search?: string- Search query for filteringpageFilter?: string- Filter by page path (e.g., "/collections/sale")
CacheOptions:
cache?: RequestCache- Request cache mode (defaults to "force-cache")revalidate?: number | false- Next.js revalidation time in seconds (defaults to 60)tags?: string[]- Next.js cache tags for selective invalidation
ResourceType Options:
ResourceType.HeroBanners- Fetch hero bannersResourceType.Announcements- Fetch announcement sections
Returns: Promise<T[]> - Array of fetched resources
Performance Features:
- Request Deduplication: Identical concurrent requests are automatically deduplicated
- Smart Caching: 60-second cache revalidation balances performance and freshness
- Parameter Normalization: Consistent cache key generation for reliable deduplication
- Error Handling: Graceful fallbacks with automatic retry on failed requests
🧩 Components
Hero Component
Responsive hero section with advanced styling capabilities.
import { Hero, IHeroStyling } from "fragment-headless-sdk";
<Hero content={heroContent} />;Props:
content: IHeroContent- Hero configuration object
IHeroContent Interface:
interface IHeroContent {
title: string;
description: string;
buttonText: string;
buttonLink: string;
imageUrl: string;
mobileImageUrl: string;
videoUrl?: string;
impressionUrl: string;
clickUrlBase: string;
styling?: IHeroStyling; // v2.0+ enhanced styling
}Available Slots:
root- Root containerdesktopWrapper/mobileWrapper- Responsive wrapperscontainer- Main content containerimage- Background image/videocontentWrapper- Content positioning wrappercontent- Text content containertitle- Hero titledescription- Hero descriptionbutton- Call-to-action button
Announcement Component
Flexible announcement component with multiple display types.
import {
Announcement,
AnnouncementType,
IAnnouncementStyling,
} from "fragment-headless-sdk";
<Announcement
content={announcementContent}
type={AnnouncementType.Announcement}
handleClose={() => setAnnouncementVisible(false)}
/>;Props:
content: IAnnouncementContent- Announcement configuration objecttype: AnnouncementType- Display typehandleClose: () => void- Close handler function
Announcement Types:
AnnouncementType.Announcement- Standard announcementAnnouncementType.Marquee- Scrolling marqueeAnnouncementType.Countdown- Countdown timer
IAnnouncementContent Interface:
interface IAnnouncementContent {
buttonType: ButtonType;
buttonText: string;
buttonLink: string;
announcementHtml: string;
counterEndDate?: string;
impressionUrl: string;
clickUrlBase: string;
styling?: IAnnouncementStyling; // v2.0+ enhanced styling
}Available Slots:
root- Root containerinner/wrapper- Layout wrappersmarqueeContainer- Marquee wrapper (marquee type)marqueeText- Scrolling text (marquee type)contentRow- Content layout (standard type)announcementText- Announcement textbutton- Action buttoncloseButton- Close buttoncountdown- Countdown container (countdown type)countdownContainer- Countdown timer containercountdownBlock- Individual time block (days, hours, etc.)countdownDigit- Countdown digit stylingcountdownLabel- Time unit labels (Days, Hours, Mins, Secs)countdownSeparator- Separator between time blocks (:)
Countdown Timer Color Tokens:
For countdown-type announcements, you can customize the timer appearance using these color tokens in styling.tokens.colors:
counterDigitColor- Color of the countdown digits (default:#FFFFFF)counterDigitBackgroundColor- Background color of the countdown digits (default:#000000)counterTextColor- Color of labels and separators (default: usescounterDigitColor)
Example:
const announcementContent = {
buttonType: ButtonType.Default,
buttonText: "Shop now",
buttonLink: "/",
counterEndDate: "2026-01-01T17:00:00.000Z",
announcementHtml: "🎉 Check out the latest products!",
styling: {
tokens: {
colors: {
text: "#1e293b",
background: "#e0e7ff",
button: "#4f46e5",
buttonText: "#ffffff",
counterDigitColor: "#ffffff",
counterDigitBackgroundColor: "#4f46e5",
counterTextColor: "#000000",
},
},
},
};🔑 API Key Setup
Before using the SDK, you need to generate an API key from your Fragment-Shopify app:
1. Generate API Key
- Install the Fragment app in your Shopify store
- Navigate to the Configuration section within the app
- Find the "API Access" section
- Click "Generate Key" to create your API key
- Save the key securely - it's only shown once!
2. API Key Format
The API key follows this format: keyId:secret
Example: bh_a1b2c3d4e5f6:your-64-char-secret-here
3. Key Management
- Only one active key per shop for security
- Keys expire after 1 year by default
- You can regenerate keys when needed (revokes the old key)
- Monitor key usage in the Configuration page
🔧 Environment Variables
Add these environment variables to your .env.local:
# Fragment-Shopify Integration
EXTERNAL_API_URL=https://your-fragment-app.vercel.app
FRAGMENT_API_KEY=bh_a1b2c3d4e5f6:your-64-char-secret🔄 Data Flow
graph TD
A[Fragment-Shopify App] --> B[API Endpoint]
B --> C[fetchResource()]
C --> D[Your React App]
D --> E[Hero/Announcement Components]
E --> F[Styling System]
F --> G[Rendered UI]- Content Creation: Editors create sections in Fragment-Shopify app
- Publishing: Sections are published and available via API
- Data Fetching: Your app calls
fetchResource()to get section data - Component Rendering: Pass data to Hero/Announcement components
- Styling Application: Advanced styling system applies design tokens, responsive design, and interactions
- UI Display: Components render beautiful, responsive, styled sections
🚨 Error Handling
The package includes built-in error handling:
// fetchResource automatically handles:
// - Missing environment variables (logs warning, returns [])
// - API errors (logs error, returns [])
// - Invalid response format (logs error, returns [])
const sections = await fetchResource({...});
// sections will always be an array, even on errorBest Practices:
- Always check if data exists before rendering:
{sections[0] && <Hero content={sections[0].content} />} - Implement fallback UI for when sections are unavailable
- Monitor console for API warnings and errors
- Use TypeScript for compile-time error prevention
📦 Package Structure
fragment-headless-sdk/
├── src/
│ ├── components/ # React components
│ │ ├── Announcement/ # Announcement components
│ │ └── Hero/ # Hero components
│ ├── constants/ # Enums and constants
│ ├── types/ # TypeScript interfaces
│ │ └── styling.ts # Advanced styling types
│ └── utils/ # Utility functions
│ └── styling.ts # Styling system utilities
└── dist/ # Compiled output📚 Documentation
- CHANGELOG.md - Release history and version notes
- STYLING.md - Advanced styling system documentation
- HERO-RESOLVERS.md - Hero component customization guide
- MIGRATION.md - Version migration guides
- PUBLISHING.md - NPM publishing guide
📝 License
MIT License - See LICENSE file for details.
