@chargebee/code-samples
A self-contained, reusable React component for displaying API code samples with syntax highlighting, language switching, and copy functionality.
Features
- Display Component: Renders pre-generated code samples with beautiful syntax highlighting
- Multi-Language: Supports 12+ languages (cURL, Node.js, Python, PHP, Ruby, Java, .NET, Go, TypeScript)
- Syntax Highlighting: Powered by Shiki
- Feature-Rich: Carousel, copy button, animations, language switcher
- Browser Export: Optimized browser API for code generation (
createCodeGenerator)
- Batch Generation: Efficient parallel code generation for SSG builds
- Structured Errors: Custom error classes with operation/language context
- Type Safety: Operation ID union types for autocomplete and validation
- Validation Script: Check sample coverage in CI/CD
- Themeable: Configurable themes and styling
Installation
pnpm add @chargebee/code-samples
Supported Languages
curl | cURL | HTTP client |
node-v2 | Node.js v2 | Legacy SDK |
node-v3 | Node.js v3 | Current SDK |
python-v2 | Python v2 | Legacy SDK |
python-v3 | Python v3 | Current SDK |
java-v3 | Java v3 | Current SDK |
java-v4 | Java v4 | Latest SDK |
php-v3 | PHP v3 | Legacy SDK |
php-v4 | PHP v4 | Current SDK |
ruby | Ruby | Current SDK |
go | Go | Current SDK |
dotnet | .NET | Current SDK |
Usage
Simple Usage (Code String)
import { CodeSamples } from '@chargebee/code-samples';
import '@chargebee/code-samples/dist/code-samples.css';
function MyPage() {
return (
<CodeSamples
codeString={`curl https://your-site.chargebee.com/api/v2/customers \\
-u test_api_key: \\
-X POST \\
-d "first_name=John&last_name=Doe"`}
language="curl"
theme="github-light"
features={{
copyButton: true,
showLineNumbers: true,
}}
/>
);
}
Multiple Pre-generated Samples
import { CodeSamples } from '@chargebee/code-samples';
import '@chargebee/code-samples/dist/code-samples.css';
function MyPage() {
const samples = {
'curl': 'curl https://...',
'node-v3': 'const chargebee = new Chargebee({...})',
'python-v3': 'import chargebee\nchargebee.configure(...)',
};
return (
<CodeSamples
samples={samples}
initialLanguage="node-v3"
theme="github-light"
features={{
carousel: true,
copyButton: true,
showLanguageSwitcher: true,
}}
/>
);
}
Props
codeString | string | ❌ | Raw code string to display (simplest usage) |
language | string | ❌ | Language identifier (required if codeString is provided) |
samples | Record<string, string> | Array<{languageSnippets: Record<string, string>}> | ❌ | Pre-generated code samples object or array |
responseData | any | ❌ | Sample response JSON to display |
initialLanguage | string | ❌ | Initial language selection (default: first language) |
theme | string | ThemeConfig | ❌ | Shiki theme name or custom config. Use "github-dark" for dark mode, "github-light" for light mode (default: "github-dark") |
highlighter | HighlighterConfig | ❌ | Shiki highlighter configuration |
features | FeaturesConfig | ❌ | Feature toggles (see below) |
className | string | ❌ | Additional CSS classes |
style | React.CSSProperties | ❌ | Inline styles |
replacements | Record<string, string> | ❌ | String replacements (e.g., {"{site}": "acme"}) |
onLanguageChange | (lang: string) => void | ❌ | Language change callback |
onCopy | (code: string) => void | ❌ | Copy callback |
onSampleChange | (index: number) => void | ❌ | Sample change callback (for carousel) |
Features Config
carousel | boolean | false | Enable carousel for multiple samples |
copyButton | boolean | true | Show copy-to-clipboard button |
animations | boolean | true | Enable fade transitions |
showHeader | boolean | true | Show/hide entire header |
showLanguageSwitcher | boolean | true | Show/hide language dropdown |
showApiExplorer | boolean | false | Show "Try in API Explorer" button |
showLineNumbers | boolean | true | Show line numbers in code blocks |
title | string | "Sample Request" | Header title |
languageFilter | string[] | undefined | Show only specific languages |
onApiExplorerClick | () => void | undefined | Callback for API Explorer button |
API Versioning
When generating code samples, you need to specify version information:
apiVersion: Chargebee API version ("v1" or "v2")
pcVersion: Product Catalog version ("v1" or "v2")
- Use
"v1" for sites created before Product Catalog 2.0
- Use
"v2" for sites with Product Catalog 2.0 enabled
- When in doubt, use
"v2" (default)
The combination of these versions determines which operation descriptors are used:
apiVersion="v1" → uses v1 operations
apiVersion="v2" + pcVersion="v1" → uses v2-pcv1 operations
apiVersion="v2" + pcVersion="v2" → uses v2-pcv2 operations (most common)
Theming
Dark/light mode is controlled by the theme prop:
theme="github-dark" - Dark mode styling (default)
theme="github-light" - Light mode styling
Any Shiki theme name is supported. The theme affects:
- Syntax highlighting colors
- Header and button styling
- Copy button appearance
<CodeSamples samples={samples} theme="github-dark" />
<CodeSamples samples={samples} theme="github-light" />
<CodeSamples samples={samples} theme="nord" />
Additional Components & Hooks
For advanced usage, you can import sub-components and hooks to build custom implementations:
Sub-Components
import {
CodeBlock,
CodeSampleHeader,
Carousel,
LanguageSwitcher
} from '@chargebee/code-samples';
<CodeBlock
code="const x = 1;"
language="typescript"
theme="github-light"
/>
Custom Hooks
import {
useSampleLoader,
useLanguageSelection
} from '@chargebee/code-samples';
function MyCustomComponent() {
const { samples, loading } = useSampleLoader({ });
const { language, setLanguage } = useLanguageSelection();
}
Constants
import {
AVAILABLE_LANGUAGES,
DEFAULT_LANGUAGE,
DEFAULT_THEME
} from '@chargebee/code-samples';
Development
Local Development Setup
pnpm install
pnpm dev
pnpm build
pnpm watch
Using the Package Locally
Option 1: Within Monorepo (Recommended)
If you're working within the cb-docs-platform monorepo, packages automatically use the workspace protocol:
{
"dependencies": {
"@chargebee/code-samples": "workspace:*"
}
}
Workflow:
- Make changes to
packages/code-samples/src/
- Build the package:
pnpm --filter @chargebee/code-samples build
- Changes are immediately available to other packages in the monorepo
- For faster iteration, use watch mode:
pnpm --filter @chargebee/code-samples watch
Option 2: External Repository (pnpm link)
For repositories outside the monorepo (e.g., cb-api-explorer):
cd packages/code-samples
pnpm link --global
cd /path/to/cb-api-explorer
pnpm link --global @chargebee/code-samples
Workflow:
- Make changes to
packages/code-samples/src/
- Build:
pnpm build (or pnpm watch for auto-rebuild)
- Changes are reflected in the linked project
- Restart dev server if needed
Unlink when done:
pnpm unlink --global @chargebee/code-samples
pnpm unlink --global
Option 3: File Protocol (Direct Path)
Reference the package directly via file path:
{
"dependencies": {
"@chargebee/code-samples": "file:../cb-docs-platform/content-migration/packages/code-samples"
}
}
Note: Requires the package to be built first. Use pnpm watch for development.
Option 4: Development Workflow (Recommended for External Repos)
For cb-api-explorer or other external repos:
-
Build the package first:
cd packages/code-samples
pnpm build
-
Use pnpm link:
pnpm link --global
pnpm link --global @chargebee/code-samples
-
Use watch mode for auto-rebuild:
cd packages/code-samples
pnpm watch
cd cb-api-explorer
pnpm dev
Important Notes:
- Always build the package before linking (
pnpm build)
- Use
pnpm watch for continuous development
- Some bundlers may need a restart to pick up changes
- The package must be built to
dist/ directory for consumption
Architecture
- generators/: Language-specific code generators (Go, Node.js, Python, etc.)
- metadata/: OpenAPI metadata extraction
- components/: React UI components
- styles/: CSS themes and animations
Code Generation vs Display
Important: The CodeSamples component is a display component - it renders pre-generated code strings. It does NOT generate code from OpenAPI specs.
To generate code from OpenAPI specs, use the generateCodeSample or generateCodeSamples functions (see Pure Function API below), then pass the result to the component:
import { CodeSamples } from '@chargebee/code-samples';
import { generateCodeSamples } from '@chargebee/code-samples';
export async function loader() {
const samples = await generateCodeSamples({
languages: ['curl', 'node-v3', 'python-v3'],
operation: 'create_a_customer',
apiVersion: 'v2',
pcVersion: 'v2',
site: 'acme-test',
apiKey: 'test_api_key',
request: {
uri: '/customers',
method: 'POST',
params: { first_name: 'John', last_name: 'Doe', email: 'john@example.com' }
}
});
return { samples };
}
function MyPage({ samples }) {
return <CodeSamples samples={samples} />;
}
Browser Export (Client-Side Generation)
For browser environments that need to generate code dynamically (e.g., API Explorer playground), use the browser export:
Basic Setup
import { createCodeGenerator } from '@chargebee/code-samples/browser';
const generator = createCodeGenerator({
apiVersion: 'v2',
pcVersion: 'v2',
site: 'acme-test',
apiKey: 'test_api_key',
cache: 'memory'
});
Generate Code Dynamically
const result = await generator.generate({
language: 'curl',
operation: 'create_a_customer',
request: {
params: { first_name: 'John', last_name: 'Doe', email: 'john@example.com' }
}
});
console.log(result.code);
React Component Example (API Explorer)
import { useState, useEffect } from 'react';
import { createCodeGenerator } from '@chargebee/code-samples/browser';
function CodeSamplePlayground({ operation, params }) {
const [code, setCode] = useState('');
const [language, setLanguage] = useState('curl');
useEffect(() => {
const generator = createCodeGenerator({
apiVersion: 'v2',
pcVersion: 'v2',
site: 'acme-test',
apiKey: 'test_key',
});
generator.generate({
language,
operation,
request: { params }
}).then(result => {
setCode(result.code);
}).catch(error => {
console.error('Failed to generate code:', error);
setCode(`// Error: ${error.message}`);
});
}, [operation, params, language]);
return (
<div>
<select value={language} onChange={e => setLanguage(e.target.value)}>
<option value="curl">cURL</option>
<option value="node-v3">Node.js</option>
<option value="python-v3">Python</option>
</select>
<pre>{code}</pre>
</div>
);
}
Prefetching Operations
Prefetch common operations to warm up the cache for faster subsequent generation:
const generator = createCodeGenerator({ });
await generator.prefetch('create_a_customer');
await generator.prefetch('list_customers');
await generator.prefetch('update_a_customer');
Runtime Validation
Validate operation IDs at runtime before generating code:
import { validateOperationId, type OperationId } from '@chargebee/code-samples/browser';
const operation: OperationId = 'create_a_customer';
const result = await generator.generate<'create_a_customer'>({
language: 'curl',
operation,
request: {
params: {
first_name: 'John',
email: 'john@example.com'
}
}
});
const userInput: string = getUserInput();
if (validateOperationId(userInput)) {
const result = await generator.generate({
language: 'curl',
operation: userInput,
request: {
params: {
first_name: 'John',
email: 'john@example.com'
}
}
});
} else {
console.error('Invalid operation ID:', userInput);
}
Note: For full type safety of request.params, you need to:
- Use the generic type parameter:
generator.generate<'create_a_customer'>()
- Extend
OperationParamsMap via module augmentation (see Pure Function API section)
Error Handling
The browser API throws structured errors:
import {
CodeGenerationError,
OperationNotFoundError,
LanguageNotSupportedError
} from '@chargebee/code-samples';
try {
const result = await generator.generate({ });
} catch (error) {
if (error instanceof OperationNotFoundError) {
console.error(`Operation not found: ${error.operation} for version ${error.version}`);
} else if (error instanceof LanguageNotSupportedError) {
console.error(`Language not supported: ${error.language}`);
console.log(`Supported: ${error.supportedLanguages.join(', ')}`);
} else if (error instanceof CodeGenerationError) {
console.error(`Failed to generate ${error.language} code for ${error.operation}`);
if (error.cause) {
console.error('Cause:', error.cause);
}
}
}
Note: The browser export uses bundled operation descriptors (no external fetching required) with optional memory caching.
Pure Function API (Server-Side)
For Node.js, LLMs, Deno, Bun, or server-side generation (SSG/SSR), use the pure function API:
import { generateCodeSample, generateCodeSamples } from '@chargebee/code-samples';
const result = await generateCodeSample({
language: 'node-v3',
operation: 'create_a_customer',
apiVersion: 'v2',
pcVersion: 'v2',
site: 'acme-test',
apiKey: 'test_api_key',
request: {
uri: '/customers',
method: 'POST',
params: { first_name: 'John', last_name: 'Doe', email: 'john@example.com' }
}
});
console.log(result.code);
console.log(result.language);
const allSamples = await generateCodeSamples({
languages: ['curl', 'node-v3', 'python-v3', 'java-v3'],
operation: 'create_a_customer',
apiVersion: 'v2',
pcVersion: 'v2',
site: 'acme-test',
apiKey: 'test_api_key',
request: {
uri: '/customers',
method: 'POST',
params: { first_name: 'John', email: 'john@example.com' }
}
});
console.log(allSamples['node-v3']);
console.log(allSamples['python-v3']);
const pregenResult = await generateCodeSample({
language: 'python-v3',
samples: {
'python-v3': 'import chargebee\nchargebee.configure(...)'
}
});
Use Cases:
- LLM/AI code generation tools
- Server-side code generation (SSG/SSR)
- CLI tools and scripts
- Non-React applications
- Testing and validation
Advanced Exports
Code Generators (Server-Side)
The code generators use pre-generated operation descriptors (bundled with the package). No external OpenAPI utils dependency is required:
import { getGenerator, getSupportedLanguages, getOperation } from '@chargebee/code-samples';
const languages = getSupportedLanguages();
const generator = getGenerator('node-v3');
const operation = getOperation('v2-pcv2', 'create_a_customer');
Type Exports
import type {
CodeSamplesPropsInterface,
GenerateCodeSampleOptions,
GenerateCodeSampleResult,
Language,
ApiVersion,
OperationDescriptor,
OperationId,
V1OperationId,
V2Pcv1OperationId,
V2Pcv2OperationId
} from '@chargebee/code-samples';
import {
CodeGenerationError,
OperationNotFoundError,
LanguageNotSupportedError
} from '@chargebee/code-samples';
Helper Components
import {
GoToApiExplorer,
TryInApiExplorer
} from '@chargebee/code-samples';
Placeholder Replacement
The code samples package supports placeholder replacement for site names and API keys. This is useful for:
- Build-time replacement: Replace placeholders during SSG build
- Runtime replacement: Replace placeholders in browser/client-side code
How Placeholders Work
By default, generated code includes placeholders like {site} and {site_api_key}:
curl https://{site}.chargebee.com/api/v2/customers \
-u {site_api_key}:
Build-Time Replacement (SSG)
In your loader/server component, generate code with placeholders, then replace them:
import { generateCodeSamples } from '@chargebee/code-samples';
const samples = await generateCodeSamples({
languages: ['curl', 'node-v3'],
operation: 'create_a_customer',
site: '{site}',
apiKey: '{site_api_key}',
});
const replacedSamples = Object.fromEntries(
Object.entries(samples).map(([lang, code]) => [
lang,
code.replace(/{site}/g, 'acme-test').replace(/{site_api_key}/g, 'test_key')
])
);
Runtime Replacement (Component)
Use the replacements prop in the CodeSamples component:
<CodeSamples
samples={samples}
replacements={{
'{site}': 'acme-test',
'{site_api_key}': 'test_api_key'
}}
/>
Common Placeholders
{site} | Chargebee site name | "your-site" |
{site_api_key} | API key | "test_api_key" |
When to Use Replacements
- Keep placeholders: When you want users to replace them manually (documentation)
- Replace at build time: When generating static docs with example values
- Replace at runtime: When displaying code in a playground with user's actual credentials
Batch Generation API (SSG)
For efficient code generation during SSG builds, use the batch API:
import { generateCodeSamplesBatch } from '@chargebee/code-samples';
const results = await generateCodeSamplesBatch({
samples: [
{
name: "Create with card",
sample: {
uri: "/customers",
method: "POST",
params: { first_name: "John" }
}
},
{
name: "Create with token",
sample: {
uri: "/customers",
method: "POST",
params: { payment_method: { type: "card" } }
}
}
],
languages: ["curl", "node-v3", "python-v3", "java-v3"],
config: {
apiVersion: "v2",
pcVersion: "v2",
operation: "create_a_customer",
site: "{site}",
apiKey: "{site_api_key}"
}
});
results.forEach(result => {
console.log(result.displayName);
console.log(result.languageSnippets);
});
This is more efficient than generating code sequentially, especially when generating for many languages and sample variations.
Validation Script
The package includes a validation script to check that all operations have corresponding sample files:
pnpm validate:samples
pnpm validate:samples:strict
Usage in CI/CD:
Add to your build process to ensure documentation completeness:
{
"scripts": {
"prebuild": "pnpm validate:samples:strict && pnpm build"
}
}
Requirements:
Set the CB_API_DOCS_BASE_PATH environment variable to point to your cb-api-documentation repository:
export CB_API_DOCS_BASE_PATH=/path/to/cb-api-documentation
The script checks that all operations defined in generated/ops have corresponding sample files in samples/cb-app/{version}/{resource}/{operation}/request/.
License
Chargebee Proprietary - See LICENSE for details.