Skip to main content

Advanced Topics

This guide covers advanced topics for ThunderID documentation development, including custom React components, Docusaurus plugins, and deployment strategies.

Creating Custom Components​

To create new custom components for ThunderID documentation:

  1. Create the component in docs/src/components/:
docs/src/components/MyComponent.tsx
tsx
import React from 'react';
import {Box, Typography} from '@wso2/oxygen-ui';

interface MyComponentProps {
title: string;
children: React.ReactNode;
}

export default function MyComponent({title, children}: MyComponentProps) {
return (
<Box sx={{ border: '1px solid', borderColor: 'divider', p: 2, borderRadius: 1 }}>
<Typography variant="h6" gutterBottom>
{title}
</Typography>
<Box>{children}</Box>
</Box>
);
}
  1. Register the component in docs/src/theme/MDXComponents.tsx:
docs/src/theme/MDXComponents.tsx
tsx
import MDXComponents from '@theme-original/MDXComponents';
import MyComponent from '@site/src/components/MyComponent';

export default {
...MDXComponents,
MyComponent,
};
  1. Use in MDX files without imports:
jsx
<MyComponent title="Example">
This is my custom component content.
</MyComponent>

Component Best Practices​

  • TypeScript: Always use TypeScript for type safety
  • Oxygen UI: Prefer Oxygen UI components for consistency
  • Accessibility: Follow WCAG guidelines
  • Responsive: Test on mobile and desktop
  • Documentation: Add JSDoc comments explaining usage
  • Props validation: Use TypeScript interfaces for props
  • Default values: Provide sensible defaults for optional props

Component Styling​

Use Oxygen UI's sx prop for styling components:

jsx
<Box 
sx={{
padding: 2,
backgroundColor: 'background.paper',
borderRadius: 1,
'&:hover': {
backgroundColor: 'action.hover',
},
}}
>
Content
</Box>

Common theme tokens:

  • primary.main, secondary.main - Brand colors
  • background.paper, background.default - Background colors
  • text.primary, text.secondary - Text colors
  • divider - Border colors
  • action.hover, action.selected - Interactive states

See Oxygen UI Theme Documentation for complete theme reference.

Custom Pages​

Create standalone pages outside the documentation structure.

Creating a Custom Page​

docs/src/pages/my-page.tsx
tsx
import React from 'react';
import Layout from '@theme/Layout';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';

export default function MyPage() {
const {siteConfig} = useDocusaurusContext();

return (
<Layout
title="My Custom Page"
description="Description for SEO">
<main>
<h1>Custom Page Content</h1>
<p>This is a standalone page.</p>
</main>
</Layout>
);
}

Access: http://localhost:5180/my-page

Landing Pages​

Create rich landing pages with custom layouts:

docs/src/pages/index.tsx
tsx
import React from 'react';
import clsx from 'clsx';
import Link from '@docusaurus/Link';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import Layout from '@theme/Layout';
import styles from './index.module.css';

function HomepageHeader() {
const {siteConfig} = useDocusaurusContext();
return (
<header className={clsx('hero hero--primary', styles.heroBanner)}>
<div className="container">
<h1 className="hero__title">{siteConfig.title}</h1>
<p className="hero__subtitle">{siteConfig.tagline}</p>
<div className={styles.buttons}>
<Link
className="button button--secondary button--lg"
to="/guides/introduction">
Get Started →
</Link>
</div>
</div>
</header>
);
}

export default function Home() {
return (
<Layout>
<HomepageHeader />
<main>{/* Your content sections */}</main>
</Layout>
);
}

Docusaurus Configuration​

Site Configuration​

Edit docs/docusaurus.config.ts for global settings:

typescript
import type {Config} from '@docusaurus/types';

const config: Config = {
title: 'ThunderID Documentation',
tagline: 'Identity and Access Management',
favicon: 'img/favicon.ico',
url: 'https://your-domain.com',
baseUrl: '/',

// GitHub Pages deployment
organizationName: 'thunder-id',
projectName: 'thunderid',

// Internationalization
i18n: {
defaultLocale: 'en',
locales: ['en'],
},

// Presets and plugins
presets: [
[
'classic',
{
docs: {
routeBasePath: '/',
sidebarPath: './sidebars.ts',
editUrl: 'https://github.com/thunder-id/thunderid/tree/main/docs/',
},
theme: {
customCss: './src/css/custom.css',
},
},
],
],
};

export default config;

Theme Configuration​

typescript
themeConfig: {
// Navbar
navbar: {
title: 'ThunderID',
logo: {
alt: 'ThunderID Logo',
src: 'img/logo.svg',
},
items: [
{
type: 'docSidebar',
sidebarId: 'guideSidebar',
position: 'left',
label: 'Guides',
},
{
href: 'https://github.com/thunder-id/thunderid',
label: 'GitHub',
position: 'right',
},
],
},

// Footer
footer: {
style: 'dark',
links: [
{
title: 'Docs',
items: [
{label: 'Getting Started', to: '/guides/introduction'},
],
},
],
copyright: `Copyright © ${new Date().getFullYear()} The ThunderID Authors`,
},

// Code highlighting
prism: {
theme: require('prism-react-renderer').themes.github,
darkTheme: require('prism-react-renderer').themes.dracula,
additionalLanguages: ['bash', 'java', 'go'],
},

// Algolia Search (if configured)
algolia: {
appId: 'YOUR_APP_ID',
apiKey: 'YOUR_SEARCH_API_KEY',
indexName: 'thunderid',
},
},

Docusaurus Plugins​

Official Plugins​

Install and configure official Docusaurus plugins:

bash
pnpm add -D @docusaurus/plugin-content-blog
pnpm add -D @docusaurus/plugin-client-redirects
pnpm add -D @docusaurus/plugin-sitemap

Configure in docusaurus.config.ts:

typescript
plugins: [
// Blog plugin
[
'@docusaurus/plugin-content-blog',
{
id: 'blog',
routeBasePath: 'blog',
path: './blog',
},
],

// Redirects plugin
[
'@docusaurus/plugin-client-redirects',
{
redirects: [
{
from: '/old-path',
to: '/new-path',
},
],
},
],

// Sitemap plugin
[
'@docusaurus/plugin-sitemap',
{
changefreq: 'weekly',
priority: 0.5,
},
],
],

Custom Plugins​

Create custom plugins for specific needs:

docs/plugins/myPlugin.ts
typescript
import type {Plugin} from '@docusaurus/types';

export default function myPlugin(): Plugin {
return {
name: 'my-custom-plugin',

async loadContent() {
// Load custom data
return {data: 'custom data'};
},

async contentLoaded({content, actions}) {
const {addRoute} = actions;
// Add custom routes
},

configureWebpack(config, isServer, utils) {
// Modify webpack config
return {
mergeStrategy: {'module.rules': 'prepend'},
module: {
rules: [
// Custom webpack rules
],
},
};
},
};
}

Search Configuration​

For smaller sites, use local search:

bash
pnpm add -D @easyops-cn/docusaurus-search-local

Configure:

typescript
themes: [
[
'@easyops-cn/docusaurus-search-local',
{
hashed: true,
language: ['en'],
highlightSearchTermsOnTargetPage: true,
explicitSearchResultPath: true,
},
],
],

For production sites, use Algolia DocSearch:

  1. Apply for DocSearch
  2. Configure in docusaurus.config.ts:
typescript
algolia: {
appId: 'YOUR_APP_ID',
apiKey: 'YOUR_SEARCH_API_KEY',
indexName: 'thunderid',
contextualSearch: true,
searchParameters: {},
searchPagePath: 'search',
},

Versioning​

Enable Versioning​

Create documentation versions for different releases:

bash
cd docs
pnpm docusaurus docs:version 1.0.0

This creates:

  • versioned_docs/version-1.0.0/: Versioned documentation
  • versioned_sidebars/version-1.0.0-sidebars.json: Versioned sidebars
  • Updates versions.json

Only docs/content/ is snapshotted. The community docs in docs/community/ are served by a separate, unversioned plugin instance and stay outside every version.

Version Configuration​

docusaurus.config.ts
typescript
presets: [
[
'classic',
{
docs: {
lastVersion: 'current',
versions: {
current: {
label: '2.0.0 (Next)',
path: 'next',
},
'1.0.0': {
label: '1.0.0',
path: '1.0.0',
},
},
},
},
],
],

Internationalization (i18n)​

Setup i18n​

Configure supported locales:

docusaurus.config.ts
typescript
i18n: {
defaultLocale: 'en',
locales: ['en', 'fr', 'es'],
localeConfigs: {
en: {
label: 'English',
direction: 'ltr',
},
fr: {
label: 'Français',
direction: 'ltr',
},
},
},

Translating Content​

Extract translatable strings:

bash
pnpm docusaurus write-translations --locale fr

Translate files in i18n/fr/:

text
i18n/
└── fr/
├── docusaurus-plugin-content-docs/
│ └── current/
│ └── guides/
│ └── introduction.md
└── docusaurus-theme-classic/
└── navbar.json

Build with Locales​

bash
pnpm docusaurus build --locale fr

Deployment​

GitHub Pages​

Deploy to GitHub Pages using the GitHub Action:

.github/workflows/deploy-docs.yml
yaml
name: Deploy Docs

on:
push:
branches: [main]
workflow_dispatch:

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 'lts/*'
- uses: pnpm/action-setup@v4

- name: Build Docs
run: make build_docs

- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs/build

Vercel​

Deploy to Vercel:

  1. Connect your GitHub repository to Vercel
  2. Configure build settings:
    • Build Command: cd docs && pnpm build
    • Output Directory: docs/build
  3. Add environment variables if needed
  4. Deploy

Netlify​

Deploy to Netlify:

netlify.toml
toml
[build]
command = "cd docs && pnpm build"
publish = "docs/build"

[[redirects]]
from = "/*"
to = "/index.html"
status = 200

Docker​

Create a Docker image:

Dockerfile.docs
dockerfile
FROM node:18-alpine AS builder

WORKDIR /app
COPY docs/package.json docs/pnpm-lock.yaml ./
RUN npm install -g pnpm && pnpm install --frozen-lockfile

COPY docs/ ./
RUN pnpm build

FROM nginx:alpine
COPY --from=builder /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Build and run:

bash
docker build -f Dockerfile.docs -t thunderid-docs .
docker run -p 8080:80 thunderid-docs

Performance Optimization​

Bundle Size​

Optimize bundle size:

docusaurus.config.ts
typescript
future: {
experimental_faster: {
swcJsLoader: true,
swcJsMinimizer: true,
swcHtmlMinimizer: true,
lightningCssMinimizer: true,
rspackBundler: true,
mdxCrossCompilerCache: true,
},
},

Image Optimization​

Use optimized images:

jsx
import ThemedImage from '@theme/ThemedImage';
import ExampleDocumentScreenLight from './assets/images/consent-login-screen-light.png';
import ExampleDocumentScreenDark from './assets/images/consent-login-screen-dark.png';

<ThemedImage
alt="Example Document Screen"
sources={{
light: ExampleDocumentScreenLight,
dark: ExampleDocumentScreenDark,
}}
/>

Lazy Loading​

Lazy load heavy components:

jsx
import React, {lazy, Suspense} from 'react';

const HeavyComponent = lazy(() => import('./HeavyComponent'));

export default function Page() {
return (
<Suspense fallback={<div>Loading...</div>}>
<HeavyComponent />
</Suspense>
);
}

Analytics​

Google Analytics​

docusaurus.config.ts
typescript
presets: [
[
'classic',
{
gtag: {
trackingID: 'G-XXXXXXXXXX',
anonymizeIP: true,
},
},
],
],

Custom Analytics​

docs/src/theme/Root.tsx
typescript
import React, {useEffect} from 'react';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';

export default function Root({children}) {
const {siteConfig} = useDocusaurusContext();

useEffect(() => {
// Custom analytics initialization
}, []);

return <>{children}</>;
}

Testing Documentation​

Check for broken links:

bash
pnpm build
# Docusaurus will report broken links during build

Visual Regression​

Use tools like Percy or Chromatic for visual regression testing.

Accessibility Testing​

bash
pnpm add -D @axe-core/cli

Test accessibility:

bash
pnpm build
pnpm serve &
axe http://localhost:5180 --exit

Troubleshooting​

Build Issues​

Memory issues:

bash
NODE_OPTIONS="--max-old-space-size=8192" pnpm build

Cache issues:

bash
rm -rf .docusaurus node_modules pnpm-lock.yaml
pnpm install
pnpm clear

Plugin Conflicts​

Check plugin compatibility and load order. Use DEBUG=* pnpm build for detailed logs.

Explore with AI

ThunderID LogoThunderID Logo

Product

DocsAPIsSDKs
© Copyright Linux Foundation Europe.For web site terms of use, trademark policy and other project policies please see https://linuxfoundation.eu/en/policies.