@contentgrowth/content-widget
v1.4.5
Published
Embed your Content Growth articles anywhere with beautiful, customizable components
Downloads
92
Maintainers
Readme
@content-growth/content-widget
Embed your Content Growth content anywhere with beautiful, customizable components.
Features
- 🎨 Beautiful UI - Pre-styled components with light/dark themes
- 🚀 Multi-Framework - React, Vue, Astro, and Vanilla JS support
- 📦 Zero Config - Works out of the box with sensible defaults
- 🎯 Type Safe - Full TypeScript support
- ⚡ Fast - Built-in caching and optimized performance
- 🎨 Customizable - Multiple layouts and display modes
- 📱 Responsive - Mobile-first design
Installation
npm install @content-growth/content-widgetQuick Start
Vanilla JavaScript
<!-- Add CSS -->
<link rel="stylesheet" href="node_modules/@content-growth/content-widget/dist/styles.css">
<!-- Add container -->
<div id="blog"></div>
<!-- Initialize widget -->
<script type="module">
import { ContentGrowthWidget } from '@content-growth/content-widget/widget';
new ContentGrowthWidget(document.getElementById('blog'), {
apiKey: 'pk_your_key_here',
layout: 'cards'
});
</script>React
import { ContentList } from '@content-growth/content-widget/react';
import '@content-growth/content-widget/styles.css';
function App() {
return <ContentList apiKey="pk_your_key_here" layout="cards" />;
}With Hooks:
import { useArticles } from '@content-growth/content-widget/react';
function CustomContentList() {
const { articles, loading, error } = useArticles({
apiKey: 'pk_your_key_here',
page: 1,
limit: 12
});
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div>
{articles.map(article => (
<div key={article.uuid}>
<h2>{article.title}</h2>
<p>{article.summary}</p>
</div>
))}
</div>
);
}Vue
<template>
<ContentList api-key="pk_your_key_here" layout="cards" />
</template>
<script setup>
import { ContentList } from '@content-growth/content-widget/vue';
import '@content-growth/content-widget/styles.css';
</script>With Composables:
<template>
<div>
<div v-if="loading">Loading...</div>
<div v-else-if="error">Error: {{ error.message }}</div>
<div v-else>
<div v-for="article in articles" :key="article.uuid">
<h2>{{ article.title }}</h2>
<p>{{ article.summary }}</p>
</div>
</div>
</div>
</template>
<script setup>
import { useArticles } from '@content-growth/content-widget/vue';
const { articles, loading, error } = useArticles({
apiKey: 'pk_your_key_here',
page: 1,
limit: 12
});
</script>Astro
---
import { ContentList } from '@content-growth/content-widget/astro';
import '@content-growth/content-widget/styles.css';
---
<ContentList apiKey="pk_your_key_here" />API Client (Framework Agnostic)
import { ContentGrowthClient } from '@content-growth/content-widget/core';
const client = new ContentGrowthClient({
apiKey: 'pk_your_key_here'
});
const { articles, pagination } = await client.listArticles({
page: 1,
limit: 12,
tags: ['tutorial']
});Components
Vanilla JS Widget
import { ContentGrowthWidget } from '@content-growth/content-widget/widget';
const widget = new ContentGrowthWidget(container, {
apiKey: 'pk_your_key_here',
baseUrl: 'https://api.content-growth.com',
layoutMode: 'cards', // 'cards' | 'rows'
displayMode: 'comfortable', // 'compact' | 'comfortable' | 'spacious'
theme: 'light', // 'light' | 'dark'
pageSize: 12,
tags: ['tutorial', 'guide'],
category: 'guides',
viewerMode: 'inline', // 'inline' | 'modal' | 'external'
mode: 'list' // 'list' | 'article-only'
});React Components
ContentList:
<ContentList
apiKey="pk_your_key_here"
layout="cards"
displayMode="comfortable"
theme="light"
pageSize={12}
tags={['tutorial', 'guide']}
category="guides"
showPagination={true}
/>ContentViewer:
<ContentViewer
apiKey="pk_your_key_here"
uuid="article-uuid"
theme="light"
showBackButton={true}
backUrl="/articles"
/>Hooks:
useArticles(options)- Fetch articles listuseArticle(options)- Fetch single articleuseCategories(options)- Fetch categoriesuseTags(options)- Fetch tags
Vue Components
ContentList:
<ContentList
api-key="pk_your_key_here"
layout="cards"
display-mode="comfortable"
theme="light"
:page-size="12"
:tags="['tutorial', 'guide']"
category="guides"
:show-pagination="true"
/>ContentViewer:
<ContentViewer
api-key="pk_your_key_here"
uuid="article-uuid"
theme="light"
:show-back-button="true"
back-url="/articles"
/>Composables:
useArticles(options)- Fetch articles listuseArticle(options)- Fetch single articleuseCategories(options)- Fetch categoriesuseTags(options)- Fetch tags
Astro Components
ContentList:
<ContentList
apiKey="pk_your_key_here"
layout="cards"
displayMode="comfortable"
theme="light"
pageSize={12}
tags={['tutorial', 'guide']}
category="guides"
showPagination={true}
/>ContentViewer:
<ContentViewer
apiKey="pk_your_key_here"
uuid={uuid}
theme="light"
showBackButton={true}
backUrl="/articles"
/>ContentCard:
A standalone article card component. Use it to display individual articles outside of ContentList.
<!-- Load by slug -->
<ContentCard
apiKey="pk_your_key_here"
slug="my-article-slug"
linkPattern="/articles/{slug}"
/>
<!-- Load by UUID -->
<ContentCard
apiKey="pk_your_key_here"
uuid="article-uuid"
/>
<!-- Use pre-loaded article data -->
<ContentCard
article={articleData}
linkPattern="/articles/{slug}"
showSummary={true}
showTags={true}
/>| Prop | Type | Default | Description |
|------|------|---------|-------------|
| apiKey | string | - | Your API key (required unless article is provided) |
| article | Article | - | Pre-loaded article data (skips API fetch) |
| slug | string | - | Load specific article by slug |
| uuid | string | - | Load specific article by UUID |
| linkPattern | string | '/articles/{slug}' | URL pattern for link |
| linkTarget | string | - | Link target attribute |
| showSummary | boolean | true | Show article summary |
| summaryMaxLength | number | - | Truncate summary at length |
| showTags | boolean | false | Show article tags |
| showCategory | boolean | true | Show category badge |
FeaturedCard:
A compact card displaying the Featured Summary with customizable styling. Perfect for landing pages.
<!-- Find latest article in category -->
<FeaturedCard
apiKey="pk_your_key_here"
category="announce"
linkPattern="/articles/{slug}"
layout="horizontal"
borderStyle="dashed"
borderColor="#e5e7eb"
padding="20px"
ctaText="Read full story"
/>
<!-- Load specific article by slug -->
<FeaturedCard
apiKey="pk_your_key_here"
slug="my-article-slug"
linkPattern="/articles/{slug}"
/>
<!-- Use pre-loaded article data (for lists) -->
<FeaturedCard
article={articleData}
linkPattern="/articles/{slug}"
/>| Prop | Type | Default | Description |
|------|------|---------|-------------|
| apiKey | string | - | Your API key (required unless article is provided) |
| article | Article | - | Pre-loaded article data (skips API fetch) |
| slug | string | - | Load specific article by slug |
| uuid | string | - | Load specific article by UUID |
| category | string | - | Filter by category |
| tags | string[] | [] | Filter by tags |
| layout | 'vertical' | 'horizontal' | auto | Card layout (auto uses article setting) |
| borderStyle | 'none' | 'line' | 'dashed' | 'none' | Card border style |
| borderColor | string | '#e5e7eb' | Border color (CSS value) |
| cardBackground | string | 'none' | Card background ('none' = transparent) |
| itemsBackground | string | '#f3f4f6' | Background for list/quote section |
| padding | string | - | Custom padding (e.g., '10px', '2rem 3rem') |
| ctaText | string | 'Read full story' | Call-to-action text |
| showAuthor | boolean | false | Show author name |
| showReadingTime | boolean | false | Show reading time |
| linkPattern | string | '/articles/{slug}' | URL pattern for link |
Featured Summary Types:
FeaturedCard supports structured JSON summaries generated via the portal wizard:
| Type | Description |
|------|-------------|
| list | Intro text on left, bulleted key points on right |
| steps | Intro text on left, numbered action steps on right |
| quote | Intro text on left, styled pullquote on right |
| classic | Simple text summary (legacy) |
Featured Cards List:
Display all articles as FeaturedCards in a grid using displayAs:
<ContentList
apiKey="pk_your_key_here"
displayAs="featured-cards"
linkPattern="/articles/{slug}"
pageSize={12}
/>| displayAs Value | Description |
|-----------------|-------------|
| 'default' | Standard card/row layout |
| 'featured-cards' | Renders each article as a FeaturedCard |
API Client
ContentGrowthClient
import { ContentGrowthClient } from '@content-growth/content-widget/core';
const client = new ContentGrowthClient({
apiKey: 'pk_your_key_here',
baseUrl: 'https://api.content-growth.com', // optional
cacheTTL: 300000, // 5 minutes, optional
debug: false // optional
});Methods
listArticles(options?)
const { articles, pagination } = await client.listArticles({
page: 1,
limit: 12,
tags: ['tutorial', 'guide'],
category: 'guides'
});getArticle(uuid)
const article = await client.getArticle('article-uuid');getCategories()
const { categories } = await client.getCategories();getTags()
const { tags } = await client.getTags();clearCache()
client.clearCache();Styling
Import the CSS file:
import '@content-growth/content-widget/styles.css';Customization
Override CSS variables:
.cg-content-list {
--cg-primary: #3b82f6;
--cg-primary-hover: #2563eb;
--cg-bg: #ffffff;
--cg-bg-secondary: #f9fafb;
--cg-text: #1f2937;
--cg-text-secondary: #6b7280;
--cg-border: #e5e7eb;
--cg-radius: 12px;
}TypeScript
Full TypeScript support with exported types:
import type {
Article,
ArticleWithContent,
Pagination,
Category,
Tag,
ClientConfig,
ListArticlesOptions,
ContentListProps,
ContentViewerProps
} from '@content-growth/content-widget/core';Getting Your API Key
- Sign in to Content Growth
- Go to Settings → API Keys
- Create a new API key
- Copy the key (starts with
pk_)
Examples
Next.js App Router
// app/articles/page.tsx
import { ContentList } from '@content-growth/content-widget/react';
import '@content-growth/content-widget/styles.css';
export default function ArticlesPage() {
return (
<main>
<h1>Articles</h1>
<ContentList apiKey={process.env.PUBLIC_CG_API_KEY!} />
</main>
);
}Nuxt 3
<!-- pages/articles.vue -->
<template>
<div>
<h1>Articles</h1>
<ContentList :api-key="apiKey" />
</div>
</template>
<script setup>
import { ContentList } from '@content-growth/content-widget/vue';
import '@content-growth/content-widget/styles.css';
const config = useRuntimeConfig();
const apiKey = config.public.cgApiKey;
</script>Vanilla HTML
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://unpkg.com/@content-growth/content-widget/dist/styles.css">
</head>
<body>
<div id="blog"></div>
<script type="module">
import { ContentGrowthWidget } from 'https://unpkg.com/@content-growth/content-widget/dist/widget/index.js';
new ContentGrowthWidget(document.getElementById('blog'), {
apiKey: 'pk_your_key_here'
});
</script>
</body>
</html>License
MIT
