Frontend Extensions
Frontend extensions are npm packages that provide React components, TypeScript API clients, and UI widgets for your Next.js application. They work seamlessly with backend extensions to create full-stack features.
User Guide This guide shows you how to use frontend extension packages in your app. You don’t need to build them yourself.
Concept: How Frontend Extensions Work
What Are Frontend Extensions?
Frontend extensions are TypeScript/React packages published to npm that:
- ✅ Provide ready-to-use React components
- ✅ Include TypeScript API clients (auto-generated from Django)
- ✅ Work with Next.js 13+ App Router
- ✅ Support both Server and Client Components
Think of them like UI component libraries (Shadcn, Radix) but specifically for Django-CFG features.
Available Packages
Your project can use these published packages:
Business Features:
@djangocfg/ext-support- Support ticket UI components@djangocfg/ext-payments- Payment processing widgets@djangocfg/ext-leads- Lead capture forms@djangocfg/ext-newsletter- Email campaign UI@djangocfg/ext-knowbase- Knowledge base components
Foundation:
@djangocfg/ext-base- Base hooks, utilities, CLI tools
Quick Start: Install Your First Extension
Step 1: Install Package
pnpm add @djangocfg/ext-support
# or
npm install @djangocfg/ext-support
# or
yarn add @djangocfg/ext-supportStep 2: Import Components
Frontend extensions have two entry points:
Server Components (Safe Everywhere)
// app/tickets/page.tsx
import { ExtSupportClient } from '@djangocfg/ext-support';
export default async function TicketsPage() {
const client = new ExtSupportClient({ baseUrl: process.env.API_URL });
const tickets = await client.support.tickets.list();
return <div>{tickets.length} tickets</div>;
}Client Components (Interactive UI)
// app/tickets/page.tsx
'use client';
import { TicketList, useTickets } from '@djangocfg/ext-support/hooks';
export default function TicketsPage() {
const { data: tickets, isLoading } = useTickets();
return <TicketList tickets={tickets} loading={isLoading} />;
}Step 3: That’s It! 🎉
The components work out of the box with your Django backend.
Installation Guide
Prerequisites
-
Backend extension enabled:
# extensions/apps/support/__cfg__.py settings = SupportSettings() -
API URL configured:
# .env.local NEXT_PUBLIC_API_URL=http://localhost:8000
Install Extension Package
pnpm add @djangocfg/ext-{name}Example packages:
# Support system
pnpm add @djangocfg/ext-support
# Payment processing
pnpm add @djangocfg/ext-payments
# Lead forms
pnpm add @djangocfg/ext-leadsUsing Extension Components
Pattern 1: Server Components (Data Fetching)
Use for SEO-friendly pages that fetch data on the server:
// app/tickets/page.tsx
import { ExtSupportClient } from '@djangocfg/ext-support';
export default async function TicketsPage() {
const client = new ExtSupportClient({
baseUrl: process.env.API_URL!,
});
const tickets = await client.support.tickets.list();
return (
<div>
<h1>Support Tickets</h1>
<div>
{tickets.map((ticket) => (
<div key={ticket.id}>
<h2>{ticket.subject}</h2>
<p>{ticket.description}</p>
</div>
))}
</div>
</div>
);
}Pattern 2: Client Components (Interactive UI)
Use for interactive features with real-time updates:
// app/tickets/client-page.tsx
'use client';
import { TicketList, useTickets, SupportLayout } from '@djangocfg/ext-support/hooks';
export default function TicketsPageClient() {
const { data: tickets, isLoading, error } = useTickets();
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error loading tickets</div>;
return (
<SupportLayout>
<TicketList tickets={tickets} />
</SupportLayout>
);
}Pattern 3: Hybrid (Server + Client)
Use for best of both worlds - SEO + interactivity:
// app/tickets/page.tsx - Server Component
import { ExtSupportClient } from '@djangocfg/ext-support';
import { TicketListClient } from './ticket-list-client';
export default async function TicketsPage() {
const client = new ExtSupportClient({ baseUrl: process.env.API_URL! });
const initialTickets = await client.support.tickets.list();
return (
<div>
<h1>Support Tickets</h1>
{/* Pass server data to client component */}
<TicketListClient initialData={initialTickets} />
</div>
);
}// app/tickets/ticket-list-client.tsx - Client Component
'use client';
import { useTickets } from '@djangocfg/ext-support/hooks';
export function TicketListClient({ initialData }) {
// Uses initialData, then fetches updates
const { data: tickets } = useTickets({ initialData });
return (
<div>
{tickets.map((ticket) => (
<TicketCard key={ticket.id} ticket={ticket} />
))}
</div>
);
}Configuration
API Base URL
Extensions need to know your Django API URL:
# .env.local
NEXT_PUBLIC_API_URL=http://localhost:8000
# Production
NEXT_PUBLIC_API_URL=https://api.yourdomain.comClient Configuration
Pass config to the API client:
import { ExtSupportClient } from '@djangocfg/ext-support';
const client = new ExtSupportClient({
baseUrl: process.env.NEXT_PUBLIC_API_URL!,
headers: {
'Authorization': `Bearer ${token}`, // Add auth
},
});Provider Setup (Optional)
For shared configuration across components:
// app/layout.tsx
import { SupportProvider } from '@djangocfg/ext-support/hooks';
export default function RootLayout({ children }) {
return (
<html>
<body>
<SupportProvider config={{ apiUrl: process.env.NEXT_PUBLIC_API_URL }}>
{children}
</SupportProvider>
</body>
</html>
);
}Then in child components:
'use client';
import { useTickets } from '@djangocfg/ext-support/hooks';
// No need to pass config - uses Provider
export function TicketList() {
const { data } = useTickets();
return <div>{data.length} tickets</div>;
}Troubleshooting
Package Not Found
Problem: Module not found: Can't resolve '@djangocfg/ext-support'
Solutions:
-
Install the package:
pnpm add @djangocfg/ext-support -
Check package name:
# Correct pnpm add @djangocfg/ext-support # Wrong pnpm add djangocfg-ext-support -
Clear cache:
rm -rf node_modules .next pnpm install
API Connection Errors
Problem: Failed to fetch or CORS error
Solutions:
-
Check API URL:
# .env.local NEXT_PUBLIC_API_URL=http://localhost:8000 # Must match Django -
Verify Django is running:
curl http://localhost:8000/cfg/support/api/tickets/ -
Check CORS settings:
# api/config.py class MyConfig(DjangoConfig): security_domains: list[str] = [ "localhost:3000", # Add your Next.js domain ]
TypeScript Errors
Problem: TypeScript can’t find types
Solutions:
-
Check package exports:
// ✅ Correct import { ExtClient } from '@djangocfg/ext-support'; import { useTickets } from '@djangocfg/ext-support/hooks'; // ❌ Wrong import { ExtClient } from '@djangocfg/ext-support/dist'; -
Restart TypeScript server:
VS Code: Cmd+Shift+P > "TypeScript: Restart TS Server" -
Check TypeScript version:
# Upgrade if needed pnpm add -D typescript@latest
“use client” Errors
Problem: You're importing a component that needs "use client"
Solutions:
Use the correct entry point:
// ❌ Wrong - importing client hooks in server component
import { useTickets } from '@djangocfg/ext-support';
// ✅ Correct - use client-safe import
import { ExtSupportClient } from '@djangocfg/ext-support'; // Server OK
// ✅ Or add 'use client' directive
'use client';
import { useTickets } from '@djangocfg/ext-support/hooks'; // Client componentComponents Not Rendering
Problem: Components render blank or throw errors
Solutions:
-
Check data is loading:
const { data, isLoading, error } = useTickets(); console.log({ data, isLoading, error }); // Debug -
Verify backend extension is enabled:
curl http://localhost:8000/cfg/support/api/tickets/ # Should return JSON, not 404 -
Check for prop mismatches:
// Check component props match data shape <TicketCard ticket={ticket} /> // Make sure 'ticket' has required fields
Best Practices
1. Use Server Components by Default
✅ Good:
// Server Component - Better SEO, faster initial load
import { ExtSupportClient } from '@djangocfg/ext-support';
export default async function Page() {
const client = new ExtSupportClient(...);
const data = await client.support.tickets.list();
return <div>{JSON.stringify(data)}</div>;
}❌ Avoid unless needed:
'use client'; // Only use when you need interactivity
import { useTickets } from '@djangocfg/ext-support/hooks';2. Environment Variables for Config
✅ Good:
const client = new ExtSupportClient({
baseUrl: process.env.NEXT_PUBLIC_API_URL!,
});❌ Bad:
const client = new ExtSupportClient({
baseUrl: "http://localhost:8000", // Hardcoded!
});3. Handle Loading & Error States
✅ Good:
const { data, isLoading, error } = useTickets();
if (isLoading) return <Skeleton />;
if (error) return <ErrorMessage error={error} />;
if (!data) return <EmptyState />;
return <TicketList tickets={data} />;4. Use TypeScript Types
import type { Ticket } from '@djangocfg/ext-support';
function TicketCard({ ticket }: { ticket: Ticket }) {
// TypeScript knows ticket.subject, ticket.description, etc.
}Common Use Cases
Use Case 1: Support Ticket Widget
Add a support ticket form to your app:
// app/support/page.tsx
'use client';
import { TicketForm } from '@djangocfg/ext-support/hooks';
export default function SupportPage() {
return (
<div>
<h1>Contact Support</h1>
<TicketForm
onSuccess={() => alert('Ticket created!')}
onError={(err) => console.error(err)}
/>
</div>
);
}Use Case 2: Payment Checkout
Add payment processing:
// app/checkout/page.tsx
'use client';
import { CheckoutForm } from '@djangocfg/ext-payments/hooks';
export default function CheckoutPage() {
return (
<CheckoutForm
amount={1000} // $10.00
currency="USD"
onSuccess={(payment) => {
console.log('Payment successful!', payment);
}}
/>
);
}Use Case 3: Lead Capture
Add a contact form:
// app/contact/page.tsx
'use client';
import { LeadForm } from '@djangocfg/ext-leads/hooks';
export default function ContactPage() {
return (
<div>
<h1>Get in Touch</h1>
<LeadForm
fields={['name', 'email', 'message']}
onSubmit={async (data) => {
console.log('Lead captured:', data);
}}
/>
</div>
);
}FAQ
Q: Which extensions are available as npm packages?
A: Check the the django-cfg repo for all published packages. Most backend extensions have corresponding frontend packages.
Q: Can I use extensions without Next.js?
A: Yes, but they’re optimized for Next.js 13+ App Router. You can use the API clients in any TypeScript/React app:
import { ExtSupportClient } from '@djangocfg/ext-support';
// Works in any JavaScript environmentQ: Do I need to install backend and frontend extensions separately?
A: Yes:
- Backend: Enable in
extensions/apps/{name}/__cfg__.py - Frontend: Install npm package
@djangocfg/ext-{name}
They work together to provide the full feature.
Q: Can I customize extension components?
A: Yes, several ways:
-
Pass props:
<TicketList theme="dark" compact={true} /> -
Wrap with your styles:
<div className="my-custom-styles"> <TicketList /> </div> -
Use composition:
import { useTickets } from '@djangocfg/ext-support/hooks'; function MyCustomTicketList() { const { data } = useTickets(); return <div>{/* Your custom UI */}</div>; }
Q: How do I authenticate API requests?
A: Pass auth headers to the client:
import { ExtSupportClient } from '@djangocfg/ext-support';
const client = new ExtSupportClient({
baseUrl: process.env.NEXT_PUBLIC_API_URL!,
headers: {
'Authorization': `Bearer ${accessToken}`,
},
});Or use the Provider:
<SupportProvider
config={{
apiUrl: process.env.NEXT_PUBLIC_API_URL,
headers: { 'Authorization': `Bearer ${token}` },
}}
>
{children}
</SupportProvider>Next Steps
Need Help? Check the troubleshooting section or join our Discord community!